代码随想录自刷1:数组篇

75 阅读2分钟

代码随想录自刷:数组篇

704.二分查找

题目链接:704.二分查找

思路:采用二分查找,注意查找的区间,个人习惯用[left, right]

有一点要注意while判断条件是否包含=,根据题目要求是查找符合的下标,所以可以出现left=right的情况发生,算出当前mid下标是自己(left=right),判断自己是否等于目标值

时间复杂度:O(logn)

class Solution {
    public int search(int[] nums, int target) {
        int left = 0, right = nums.length - 1;
        int mid;
        while (left <= right) {
            mid = left + (right - left) / 2;
            if (nums[mid] == target) {
                return mid;
            } else if (nums[mid] < target) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
        return -1;
    }
}

27.移除元素

题目链接:27.移除元素

数组的特性,数组的内存地址是连续的,无法删除数组中某个元素,只能将其覆盖掉!直接覆盖要如何实现操作?也是用两个指针来完成!

个人采用的是快慢指针(也可以用双向指针:相向双指针法改变数组中元素顺序,快慢指针法不改变数组中元素顺序)

快指针一直遍历元素,当当前元素不等于删除元素时,慢指针指向的元素被赋值为当前元素值,然后慢指针++,如此直到快指针走完数组,此时慢指针就表示当前新数组的长度!

class Solution {
    public int removeElement(int[] nums, int val) {
        int left=0;
        for(int right=0;right<nums.length;right++){
            if(nums[right]!=val){
                nums[left]=nums[right];
                left++;
            }
        }
        return left;
    }
}

参考代码随想录

补充:双向指针写法:

//相向双指针法
class Solution {
    public int removeElement(int[] nums, int val) {
        int left = 0;
        int right = nums.length - 1;
        while(right >= 0 && nums[right] == val) right--; //将right移到从右数第一个值不为val的位置
        while(left <= right) {
            if(nums[left] == val) { //left位置的元素需要移除
                //将right位置的元素移到left(覆盖),right位置移除
                nums[left] = nums[right];
                right--;
            }
            left++;
            while(right >= 0 && nums[right] == val) right--;
        }
        return left;
    }
}

977.有序数组的平方

有序数组的平方

思路:既然会用双指针,就用双指针解决!(数组很多问题都可以考虑双指针!效率更快)

根据题意:数组是递增的(包含负数),这样当前最大值只会在数组两头之一:

  1. 谁最大谁先放到新数组中(从后往前加入)
  2. 指向最大元素的指针此时往前or往后走,另一个指针不变,继续下一次的比较
public int[] sortedSquares(int[] nums) {
        int[] res=new int[nums.length];
        int left=0;
        int right=nums.length-1;
        int end=nums.length-1;
        while(left<=right){
            if(nums[left]*nums[left]>nums[right]*nums[right]){
                res[end--]=nums[left]*nums[left];
                left++;
            }else{
                res[end--]=nums[right]*nums[right];
                right--;
            }
        }
        return res;
    }

209.长度最小的子数组(滑动窗口)

209. 长度最小的子数组

不考虑暴力双for解法,重点在滑动窗口!滑动窗口内的容量是有限的:

  • 当窗口内的元素累加超过该容量时,就从头去掉元素。直到小于容量为止
  • 当窗口内的元素累加小于该容量时,就从尾加入元素。直到超过容量为止

滑动窗口其实也是靠两个指针来实现!一个指向头部,一个指向尾部。

public int minSubArrayLen(int target, int[] nums) {
        int left=0;
        int sum=0;
        int size=Integer.MAX_VALUE;;
        for(int i=0;i<nums.length;i++){
            sum+=nums[i];
            System.out.println(sum);
            while(sum>=target){
                size=Math.min(size,i-left+1);
                sum-=nums[left];
                left++;
            }
        }
        return size==Integer.MAX_VALUE ? 0 : size;
    }

59. 螺旋矩阵 II

59. 螺旋矩阵 II

一开始难以理解,但记得要一条边、一条边的处理!遇到转角统一交给自己处理or下一条处理!不能混搭

图片参考代码随想录 20220922102236.png

思路:j用于记录循环第几圈,从0开始。从上方左到右开始(每条边的最后一格子交给自己处理)

public int[][] generateMatrix(int n) {
        int[][] res=new int[n][n];
        int count=1,j=0;    //j等于循环圈的次数从0开始
        while(count<=n*n){
            //i<3
            for(int i=j;i<n-j;i++){
                res[j][i]=count++;//i=2,j=0  
            }
            // i=1,i<3
            for(int i=j+1;i<n-j;i++){
                res[i][n-j-1]=count++;//col=3-0-1=2
            }
            //i=1,i>=0
            for(int i=n-j-2;i>=j;i--){
                res[n-j-1][i]=count++;  //row=2
            }
            //i=1,i>0
            for(int i=n-j-2;i>j;i--){
                res[i][j]=count++; //col=0
            }
            j++;
        }
        return res;
    }