• 力扣刷题笔记



    前言

    本博客仅做学习笔记,如有侵权,联系后即刻更改

    科普:


    学习路线

    参考文章

    时间/空间复杂度

    时间复杂度

    时间复杂度考虑最坏时间复杂度

    • T(n) = O(f(n))
      f(n) 是算法代码执行的总步数,也叫操作数
    • O(logn)
      对于对数复杂度来说,不管是以 2、3 为底,通通记作 O(logn)
      在这里插入图片描述
    • 常见时间复杂度
      在这里插入图片描述

    空间复杂度

    在衡量代码的空间复杂度的时候,只关心运行过程中临时占用的内存空间

    • n 作为数据集大小,f(n) 指的是规模 n 所占存储空间的函数
      在这里插入图片描述

    堆/栈

    程序运行时所需的内存空间分为 固定部分,和可变部分
    在这里插入图片描述

    数组

    在这里插入图片描述

    知识点

    for的增强型循环

    • 增强for循环遍历数组时使用的普通for循环,而遍历集合时使用的Iterator迭代器
    • 在使用增强型for循环不支持遍历时删除元素
    • 使用增强型for循环时,对遍历的集合需要做null判断,不然可能引发空指针异常。

    快慢指针

    • 使用速度不同的指针(可用在链表、数组、序列等上面),来解决一些问题
    • 快指针 fast 指向当前要和 val 对比的元素,慢指针 slow 指向将被赋值的位置

    滑动窗口

    • 一般就用在数组或者字符串上
    • 滑动:窗口可以按照一定的方向移动。
    • 窗口:窗口大小可以固定,也可以不固定,此时可以向外或者向内,扩容或者缩小窗口直至满足条件

    模拟题

    • 模拟题本身不涉及算法,就是单纯根据题目所描述的模拟整个过程从而得到最后的结果

    力扣704题-二分查找

    确定区间为左闭右闭

    • 左节点可以等于右节点
    • middle要向前/后移动一位

    数组的特点

    • 数组下标都是从0开始的
    • 数组内存空间的地址是连续的
    class Solution {
        public int search(int[] nums, int target) {
            // 避免输入的target过大或过小
            if (target < nums[0] || target > nums[nums.length - 1]) 
                return -1;
             int left = 0,
             right = nums.length-1,
             middle;
             while(left <= right){
                 middle = left + (right-left)/2;
                 if(nums[middle] == target)
                    return middle;
                 else if(nums[middle] > target)
                     right = middle-1;
                 else 
                 	 left = middle+1;
             }
             return -1;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    相关题目

    力扣35-搜索插入位置
    class Solution {
        public int searchInsert(int[] nums, int target) {
            int len = nums.length -1;
            // 提前判断是否在区间内
            if(target < nums[0])
                return 0;
            else if(target > nums[len])
                return len+1;
            // 左闭右闭区间
            int left = 0, right = len, middle = 0;
            while(left <= right){
                middle = left + (right - left)/2;
                // target在右区间
                if(nums[middle] < target)
                   left = middle+1;
                // target在左区间
                else if(nums[middle] > target)
                  right = middle-1;
                else return middle; 
            }
            // 目标值插入数组中 
            return right+1;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    力扣34-在排序数组中查找元素的第一个和最后一个位置
    class Solution {
        public int[] searchRange(int[] nums, int target) {
            int location = binarySearch(nums,target);
    
            if(location == -1){
                return new int[] {-1,-1};
            }
            // 确定左右边界
            int leftBorder =location ,rightBorder = location;
            while(leftBorder-1 >= 0 && nums[leftBorder-1] == nums[location]){
                leftBorder--;
            }
            while(rightBorder+1 < nums.length && nums[rightBorder+1] == nums[location]){
                rightBorder++;
            }
            return new int [] {leftBorder,rightBorder};
    
        }
    
    // 二分查找
        public int binarySearch(int[] nums, int target){
            int len = nums.length;
            //  先判断是否在数组内
            if(nums.length == 0)
                return -1;
            else if(target < nums[0]) 
                return -1;
            else if(target > nums[len-1])
                return -1;
            // 左闭右闭
            int left = 0, right = len -1, middle = 0;
            while(left <= right){
                middle = left + (right-left)/2;
                if(target == nums[middle]){
                     return middle;
                }else if(target > nums[middle]){
                    left = middle +1;
                }else {
                    right = middle -1;
                }
            }
            return -1;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    力扣69-x的平方根
    class Solution {
        public int mySqrt(int x) {
            int left = 0, right = x, middle = 0, ans = -1;
            while(left <= right){
                middle = left + (right - left)/2;
                if((long)middle*middle <= x){
                    ans = middle;
                    left = middle +1;
                }else 
                right = middle -1;
            }
             return ans;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    力扣367-有效的完全平方数
    class Solution {
        public boolean isPerfectSquare(int num) {
            int left = 0, right = num, middle = 0;
            while(left <= right){
                middle = left + (right - left)/2;
                if((long)middle*middle == num){
                    return true;
                }else if((long)middle*middle < num)
                    left = middle+1;
                else right = middle -1;
            }
             return false;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    力扣27题-移除元素

    移除元素

    • 是快慢指针的经典题目

    暴力双层循环

    class Solution {
        public int removeElement(int[] nums, int val) {
            int num = nums.length;
            for(int i=0; i<num; i++){
                if(nums[i] == val){
                    for(int j=i; j<num-1; j++){
                        nums[j] = nums[j+1];
                    }
                    num--;
                    i --;
                }
            }
            return num;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    快慢指针

    class Solution {
        public int removeElement(int[] nums, int val) {
            int slow = 0;
            int fast = 0;
            for(; fast<nums.length; fast++){
                if(nums[fast] != val){
                    nums[slow] = nums[fast];
                    slow++;
                }
            }
            return slow;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    双向指针

    class Solution {
        public int removeElement(int[] nums, int val) {
            int left = 0;
            int right = nums.length -1;
            while(left <= right){
                // 找左边等于val的元素
                while(left <= right && nums[left] != val)
                    left ++;
                // 找右边不等于val的元素
                while(left <= right && nums[right] == val)
                    right --;
                if(left < right)
                    nums[left ++] = nums[right --]; 
            }
            return left;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    相关题目

    力扣26-删除有序数组中的重复项
    class Solution {
        public int removeDuplicates(int[] nums) {
            if(nums == null || nums.length == 0) return 0;
            int slowIndex = 0, fastIndex = 0;
            while(fastIndex < nums.length){ 
                if(nums[fastIndex] != nums[slowIndex]){
                    if(fastIndex - slowIndex > 1)
                        nums[slowIndex+1] = nums[fastIndex];
                    slowIndex ++;
                }
                fastIndex ++;
            }
            return slowIndex +1;        
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    力扣283-移动零
    class Solution {
        public void moveZeroes(int[] nums) {
            int slowIndex = 0;
            for(int fastIndex = 0; fastIndex < nums.length; fastIndex++){
                if(nums[fastIndex] != 0)
                    nums[slowIndex++] = nums[fastIndex];
            }
            for(int i = slowIndex; i < nums.length; i++){
                nums[i] = 0;
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    力扣844-比较含退格的字符串

    使用栈实现退格

    class Solution {
        public boolean backspaceCompare(String s, String t) {
           return resolveStr(s).toString().equals(resolveStr(t).toString());
        }
        public StringBuilder resolveStr(String s){
            StringBuilder sta = new StringBuilder();
            for(char ch : s.toCharArray())
                if(ch != '#')
                     sta.append(ch);
                else if(sta.length() > 0) 
                    sta.deleteCharAt(sta.length() -1);
            return sta;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    双指针从后往前

    class Solution {
        public boolean backspaceCompare(String S, String T) {
            int sSkipNum = 0; // 记录S的#数量
            int tSkipNum = 0; // 记录T的#数量
            int i = S.length() - 1;
            int j = T.length() - 1;
            while (true) {
                // 从后向前遍历S
                while (i >= 0) {
                    // 如果为#,计数加一 
                    if (S.charAt(i) == '#') sSkipNum++;
                    else {
                        // #的计数不为零,要过一轮
                        if (sSkipNum > 0) sSkipNum--;
                        // 直到#的个数为0,跳出和T的字符比对
                        else break;
                    }
                    i--;
                }
                while (j >= 0) { 
                    if (T.charAt(j) == '#') tSkipNum++;
                    else {
                        if (tSkipNum > 0) tSkipNum--;
                        else break;
                    }
                    j--;
                }
    
                // 先检验 S 或者 T 是否遍历到头了
                if (i < 0 || j < 0) break; 
                // 检验跳出时的字符是否相同,不同则可以跳出最外层循环,返回false
                if (S.charAt(i) != T.charAt(j)) return false;
                i--;j--;
            }
            // 说明S和T同时遍历完毕
            if (i == -1 && j == -1) return true;
            return false;
        }
    };
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    力扣977题-有序数组平方排序

    双指针法来解决,left 指向下标 0,right 指向下标 n - 1

    class Solution {
        public int[] sortedSquares(int[] nums) {
           int right = nums.length-1, left = 0;
           int array[] = new int [nums.length];
           int pos = nums.length-1;
    
           while(left <= right){
               nums[left] = Math.abs(nums[left]);
               nums[right] = Math.abs(nums[right]);
               if(nums[left] > nums[right])
                   array[pos--] = (int)Math.pow(nums[left++], 2);
                else {
                    array[pos--] = (int)Math.pow(nums[right--], 2);
                }
           } 
           return array;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    力扣209题-长度最小子数组

    滑动窗口

    class Solution {
        public int minSubArrayLen(int target, int[] nums) {
            int right=0, left=0, sum=0, num=Integer.MAX_VALUE;
            for(; right<nums.length;){
                sum += nums[right++];
                while(sum >= target){
                    num = Math.min(num, right-left);
                    sum -= nums[left++];
                }
            }
            return num == Integer.MAX_VALUE ? 0 : num;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    力扣59题-螺旋矩阵

    • 题目解析
      这是一道模拟题,难度中等,面试出现频率极高

    • 时空复杂度分析
      矩阵大小为 n²,需要全部遍历且填充,所以时间复杂度为 O(n²)
      此外额外维护了一个大小为 n² 的结果矩阵,所以空间复杂度为 O(n²)

    class Solution {
        public int[][] generateMatrix(int n) {
            int w[][]= new int [n][n];
            int s=0,x=n-1,z=0,r=n-1;
            int sum=1,i;
            while(sum <= n*n){
                for(i=z; i<=r; i++)
                w[s][i] = sum++;
                s++; 
                for(i=s; i<=x; i++)
                w[i][r] = sum++;
                r--;
                for(i=r; i>=z; i--)
                w[x][i] = sum++;
                x--;
                for(i=x; i>=s; i--)
                w[i][z] = sum++;
                z++;
            }
            return w;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    总结

    小小励志

    有些事你现在不做,一辈子都不会做了。
    如果你想做一件事,全世界都会为你让路。
    《搭车去柏林》

  • 相关阅读:
    Typora~阿里云OSS+Typora+PicGo解决方案
    一种KV存储的GC优化实践
    Go工作空间
    【《Successful PhD Journey》EP02 】学习笔记
    使用jmeter+ant进行接口自动化测试(数据驱动)
    【LeetCode每日一题】——1217.玩筹码
    .netcore 连接 apache doris
    学妹学Java(一)
    Docker入门教程(详细)
    ubuntu18.04.1LTS 编译安装ffmpeg详解
  • 原文地址:https://blog.csdn.net/qq_51922077/article/details/127639559