【代码随想录】刷题Day1【数组】

102 阅读3分钟

一、704. 二分查找

// 左闭右开
public int search(int[] nums, int target) {
    int n = nums.length;

    int left = 0, right = n;

    while(left < right) {
        int mid = left + ((right-left)>>>1);

        if(nums[mid] > target) {
            right = mid;
        } else if(nums[mid] < target) {
            left = mid+1;
        } else {
            return mid;
        }
    }

    return -1;
}

// 左闭右闭
public int search1(int[] nums, int target) {
    int n = nums.length;

    int left = 0, right = n-1;

    while(left <= right) {
        int mid = left + ((right-left)>>>1);

        if(nums[mid] > target) {
            right = mid-1;
        } else if(nums[mid] < target) {
            left = mid+1;
        } else {
            return mid;
        }
    }

    return -1;
}

常见问题:

1.奇怪的左右边界问题,到底是左闭右开还是左闭右闭区间

2.循环判断是小于还是小于等于

3.更新左右下标是加1减1还是不做操作

一切根据定义的数组下标实现后续操作!!!

左闭右开还是左闭右闭区间,其实都能选,这里是不唯一的

左闭右开

  1. 问题:首先,左闭右开说明右边边界是无效的,它不被包含在求值本身中;
  2. 循环判断:那么循环判断根据区间有效性,不能出现相等,因为如果左右相等了,数组的条件又是不相等,那不就是矛盾的地方吗,因此我们不选择在循环中出现等于的符号;
  3. 下标加1减1:在更新左右下标中,更新左边,mid已经判断不是所求的值,左边又是闭区间,我们需要刨除掉,因此需要对左边进行=mid+1,更新右边,mid不是所求,但是右区间也是不被算进去的,那么我们只要更新到mid即可

左闭右闭

  1. 左右边界问题:首先,左闭右闭说明右边边界是有效的,它包含在求值本身中;
  2. 循环判断:那么循环判断根据区间有效性,一定要能出现相等,因为如果左右相等了,数组的条件也是相等,那么我们其实还要对该值进行判断,因为其在数组中有效
  3. 下标加1减1:在更新左右下标中,更新左边,mid已经判断不是所求的值,左边又是闭区间,我们需要刨除掉,因此需要对左边进行=mid+1,更新右边,mid是所求,右区间也是被算进去的,mid我们已经求过了不在范围内,那么我们要更新到mid-1

推荐题目

  1. 35. 插入位置
  2. 34. 在排序数组中查找元素的第一个和最后一个位置

二、27. 移除元素

思路

双指针法:快指针用来判断元素是否需要留下来,慢指针表示有效元素

public int removeElement(int[] nums, int val) {
    int slow = 0, fast = 0;
    while (fast < nums.length) {
        if(val == nums[fast]) {
            fast++;
        } else {
            nums[slow++] = nums[fast++];
        }
    }

    return slow;
}

三、209. 长度最小的子数组

思路

  1. 暴力:双层for循环
  2. 滑动窗口:拥有两个指针slow,fast(fast一直往前走,知道区间和 > target,这时就轮到slow走了,逐渐逼近 target,把满足条件的数组的长度记录下来,每次满足条件都进行一下判断,最终返回最小的)
public int minSubArrayLen(int target, int[] nums) {
    int sum = 0;
    int ret = nums.length + 1;
    int slow = 0;
    for (int fast = 0; fast < nums.length; fast++) {
        sum += nums[fast];
        while (sum >= target) {
            if(sum >= target) {
                ret = Math.min(fast - slow + 1,ret);
            }
            sum -= nums[slow++];
        }
    }

    return ret == nums.length + 1 ? 0 : ret;
}

推荐题目

  1. 904. 水果成篮
  2. 76. 最小覆盖子串

四、59. 螺旋矩阵 II

主要代码如下图所示,核心:控制边界条件判断

image.png

public int[][] generateMatrix(int n) {
        int startx = 0, starty = 0;
        int count = 1;
        int[][] ret = new int[n][n];
        // 控制列的边界
        int offset = 1;

        // 循环的圈数
        int m = n / 2;
        while (m > 0) {
            int i = startx;
            int j = starty;
            for (; j < n - offset; j++) {
                ret[i][j] = count++;
            }

            for (; i < n-offset; i++) {
                ret[i][j] = count++;
            }

            for (; j > starty; j--) {
                ret[i][j] = count++;
            }

            for (; i > startx; i--) {
                ret[i][j] = count++;
            }

            startx++;
            starty++;
            offset++;
            m--;
        }
        
        // 奇数的话会有一个中心点
        if(n % 2 == 1) {
            ret[startx][starty] = count;
        }

        return ret;
    }

推荐题目

  1. 54. 螺旋矩阵
  2. BC134 蛇形矩阵