Day2 | 977有序数组的平方&209长度最小的子数组&59螺旋矩阵Ⅱ

89 阅读4分钟

有序数组的平方 LeetCode 977

题目链接:LeetCode 977 - 简单

思路

看到题目的第一想法就是比较数组中大于0和小于0部分平方后的大小。这样子达到了O(n)的时间复杂度,但是新增了一个数组,内存消耗会比较高。

O(n)时间复杂度:

java
class Solution {
    public int[] sortedSquares(int[] nums) {
        int n = nums.length;
        int[] newNums = new int[n];
        int index = 0;
        for(;index < n;index++){
            if(nums[index]>=0){
                break;
            }
        }
        int left=index-1,right=index;
        index=0;
        while((left>=0 && left<n) || (right<n && right>=0 )){
            if(left>=0&&right<n){
                if(nums[left]*nums[left]>nums[right]*nums[right]){
                    newNums[index]=nums[right]*nums[right];
                    right++;
                }else{
                    newNums[index]=nums[left]*nums[left];
                    left--;
                }
            }else if(left>=0){
                newNums[index]=nums[left]*nums[left];
                left--;
            }else if(right<n){
                newNums[index]=nums[right]*nums[right];
                right++;
            }
            index++;
        }
        return newNums;
    }
}

O(n)时间复杂度(代码随想录):

java
class Solution {
    public int[] sortedSquares(int[] nums) {
        int right = nums.length - 1;
        int left = 0;

        int[] result = new int[nums.length];
        int index = right;
        while(left<=right){
            if(nums[left]*nums[left] > nums[right]*nums[right]){
                result[index] = nums[left]*nums[left];
                left++;
            }else{
                result[index] = nums[right]*nums[right];
                right--;
            }
            index--;
        }
        return result;
    }
}

总结

  1. 刚开始写代码的时候,没有考虑到只有小于0的数组
  2. 看了代码随想录的解析后,同样是采用双指针的方式,但是从数组内部到数组的首位写的代码相较于从数组首位向数组两端的代码,编写更复杂,更加不容易理解。
  3. 此后需要多多想多个方法再进行动笔,考虑更加全面。

长度最小的子数组 LeetCode 209

题目链接:LeetCode 209 - 中等

思路

第一次看到题目。看成了找到等于target的程度最小的连续子数组。并且只想到了暴力求解法(两个for),该题的暴力求解的方式时间超时。 因此后来改为滑动窗口来解答。

滑动窗口法:

java
class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int sum=0,left=0,result=Integer.MAX_VALUE;
        for(int right = 0 ; right < nums.length; right++){
            sum += nums[right];
            while(sum>=target){
                result = Math.min(result,right-left+1);
                sum -= nums[left];
                left++;
            }
        }
        return (result==Integer.MAX_VALUE)?0:result;
    }
}

暴力求解(两个for):

java
class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int result = Integer.MAX_VALUE;
        for(int i = 0; i < nums.length; i++){
            int sum = 0;
            for(int j = i; j < nums.length; j++){
                sum += nums[j];
                if(sum >= target){
                    result = Math.min(result,j-i+1);
                    break;
                }
            }
        }
        return (result==Integer.MAX_VALUE)?0:result;
    }
}

总结

  1. 在看题时需要警惕一些临界条件
  2. 学到了滑动窗口这种方法
  3. 有一种较难的前缀和+二分查找的方式:

首先,方法一采用暴力枚举,也是最清晰易懂的,我们以每个下标为出发点,搜遍所有区间。但是聪明的小朋友们发现,每个下标开始的这个遍历过程计算了很多重复的区间,比如1,2,3,4 。以1为下标时计算了+2、+3、+4 ; 以2为下标时计算了+3、+4,像这种避免区间和重复计算的优化方法,我们想到了前缀和,可以O(1)时间迅速得到任意区间的和问题。 然后 ,我们可以很容易得改良问题为 求s[j] - s[i] >=target ,可是这种做法如果不加改变,就是在前缀和数组上进行类似方法一的暴力枚举,枚举每一个i后面的下标j 最后,我们发现稍作变化,像这种线性的求值问题,联合二分查找可以做到 求 s[j] >=s[i]+target. 由此引出前缀和+二分查找,官方解法可能确实没有将思路解释清楚,我们从优化遍历过程、避免重复计算的前缀和到二分,最好还是理清思考顺序,这样方便我们的举一反三。

java
class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int[] sums = new int[nums.length+1];
        int result = Integer.MAX_VALUE;
        for(int i = 1; i <= nums.length;i++){
            sums[i] = sums[i-1] + nums[i-1];
        }
        for(int i = 1; i <= nums.length;i++){
            int targetnum = target + sums[i-1];
            int bound = Arrays.binarySearch(sums,targetnum);
            if(bound<0){
                bound = -bound - 1;
            }
            if(bound <= nums.length){
                result = Math.min(result,bound - i + 1);
            }
        }
        return result == Integer.MAX_VALUE ?0:result;
    }
}

螺旋矩阵Ⅱ LeetCode 59

题目链接:LeetCode 59 - 中等

思路

看到题目,有思路但是不知道如何编写代码。

滑动窗口法:

java
class Solution {
    public int[][] generateMatrix(int n) {
        int[][] result = new int[n][n];
        int i=0,j=0;
        int num=1;
        int loop=0,start=0;
        while(loop++ < n / 2){
            for(j=start;j<n-loop;j++){
                result[start][j]=num++;
            }
            for(i=start;i<n-loop;i++){
                result[i][j]=num++;
            }
            for(;j>=loop;j--){
                result[i][j]=num++;
            }
            for(;i>=loop;i--){
                result[i][j]=num++;
            }
            start++;
        }
        if (n % 2 == 1) {
            result[start][start] = num;
        }
        return result;
    }
}

总结

还是需要多练习算法题