代码随想录算法训练营第二天|977.有序数组的平方,209.长度最小的子数组,59.螺旋矩阵II

882 阅读2分钟

977.有序数组的平方

题目链接:977.有序数组的平方

思路:双指针思想,数组是有序的且含有负数,其中元素的平方一定是两边最大。定义两个指针,从两端开始向中间靠近,每次比较两个指针的元素平方大小,将较大的一个存入结果数组。(注意结果数组是从小到大的,所以要从后往前开始存入)

时间复杂度:O(n),空间复杂度O(n)

class Solution {
    public int[] sortedSquares(int[] nums) {
        int[] result = new int[nums.length];
        int left = 0, right = nums.length - 1;
        int i = right;
        while (left <= right) {
            if (nums[left] * nums[left] >= nums[right] * nums[right]) {
                result[i--] = nums[left] * nums[left];
                left++;
            } else {
                result[i--] = nums[right] * nums[right];
                right--;
            }
        }
        return result;
    }
}

209.长度最小的子数组

题目链接:209.长度最小的子数组

思路:滑动窗口,两个指针代表窗口的左右边界,右边界一直遍历最后,当窗口中元素和大于目标值的时候,更新结果,并且左边界往前走一步。(注意:这里一定是窗口右边界遍历一次,然后根据条件更新左边界。如果左边界作为遍历条件,一次循环是解不出来的。)

时间复杂度:O(n)

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int i = 0; // i代表窗口左边界
        int count = nums[i]; // count存放窗口中元素和
        if (count >= target) {
            return 1;
        }
        int result = nums.length + 1; // 定义结果为最大
        for (int j = 1; j < nums.length; j++) { // j为窗口右边界
            count += nums[j];
            while (count >= target) { // 窗口中元素符合题意,更新结果,更新左边界和count
                result = result < (j - i + 1) ? result : (j - i + 1);
                count -= nums[i++];
            }
        }
        return result == nums.length + 1 ? 0 : result;
    }
}

59.螺旋矩阵II

题目链接:59.螺旋矩阵II

思路:本题主要考察代码逻辑逻辑能力,执行了很多次才找到正确解法。借用代码随想录中的图片容易理解

2020121623550681.png

时间复杂度:O(n)

class Solution {
    public int[][] generateMatrix(int n) {
        int[][] result = new int[n][n];
        int i = 0, j = 0;
        int num = 1;
        int k = 0; // k代表循环的次数
        while (k < n / 2 && num <= n * n) {
            for (;j < n - 1 - k; j++) {
                result[i][j] = num++;
            }
            for (;i < n - 1 - k; i++) {
                result[i][j] = num++;
            }
            for (;j > 0 + k; j--) {
                result[i][j] = num++;
            }
            for (;i > 0 + k; i--) {
                result[i][j] = num++;
            }
            i++;
            j++;
            k++;
        }
        if (n % 2 != 0) { // 如果中间只剩一个,需要单独处理
            result[i][j] = num;
        }
        return result;
    }
}

数组题目总结

数组的题目的主要解法有以下几种

二分法

遇到有序数组,需要进行查找操作的时候,可以考虑二分

双指针法

双指针法里面比较重要的,是快慢指针法。当一个指针无法解题,或者需要使用一次循环完成两次循环里才能解决的问题时,需要考虑使用双指针。双指针的种类很多,滑动窗口也可以看作双指针法。

滑动窗口

滑动窗口是一种很巧妙的方法,可以不断的调节子序列的位置。当我们遇到需要查找符合条件的子序列时,可以考虑滑动窗口。

模拟行为

这种题目就是考察代码逻辑能力,但是要注意遵守循环不变量原则,二分法中也用到了循环不变量原则,其实就是保证循环过程中,我们定义的循环范围不要改变,例如:不要再一个开区间的循环中,做闭区间的循环的操作,这样的代码逻辑十分混乱。