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

977.有序数组的平方

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

初印象

在昨天积极做扩展题目时,已经接触过本道题目,当时的方法是双指针法

代码

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

        while (left <= right){
                if (nums[left] * nums[left] > nums[right] * nums[right]){
                    arr[i] = nums[left] * nums[left];
                    i--;
                    left++;
                }
                if (nums[left] * nums[left] <= nums[right] * nums[right]){
                    arr[i] = nums[right] * nums[right];
                    i--;
                    right--;
                }
        }
        return arr;
    }
}

心得

本题求解较为顺利,思路也比较清晰。

出了一点小的错误:

对于如下示例:

输入:nums = [-7,-3,2,3,11]
输出:[4,9,9,49,121]

问题:我比较纠结在left和right比较过程中,-3和3的平方都是9,而数组中有两个9,是否需要在if语句大小比较中,加入两个等号。结果在只有一个元素的数组,如 [1] 报错。

解答:其实双指针在移动过程中,只会把符合条件的数加入数组,且另一个指针不动,如-3和3比较中,把3的平方9加入新数组,right指针移动,但-3的指针left不动,接下来是-3和2进行比较,同样能将-3的平方9加入数组中。

思维:不要太跳脱,在大脑中像虚拟机一样将代码一步步执行一遍试试看。

209.长度最小的子数组

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

初印象

除了暴力求解,暂无思路。本题使用的滑动窗口思想很好理解,自己之前没太接触过。

滑动窗口法:不断调整子序列的终止位置和起始位置,从而得到我们想要的结果,本质还是双指针,时间复杂度为O(n)

思路分析

本题的重点在于理解for循环代表的是起始指针还是终止指针。按照最常规思路,一般是起始指针,那么终止指针还是要遍历,时间复杂度与暴力求解时的两个for循环相同。

终止指针向后移动,直到sum+=nums[j] >=target,再去移动起始指针。看似也是两个循环,但起始指针循环的次数很少。判断i到j区间的最小子数组,i作为起始指针向后移动,sum=sum-nums[i],以此来寻找最小子数组。

代码

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

错误集锦

  1. 在关于j的for循环中,应该是sum += nums[j],而自己写成了sum += j。无脑错误,以后要注意。
  2. 关于最后的return 要考虑到没有符合条件的子数组,不能简单地return result;需要有一步return result == Integer.MAX_VALUE ? 0 : result;判断
  3. 关于result的赋值,自己最开始简单赋值为nums.length 结果是错误的,因为存在最小子数组长度为nums.length的情况,这时候结果会是0.所以一开始result的赋值应该是大于nums.length的任意整数。

心得

学会了滑动窗口的思路。除了常规思路,也要试着从另一个角度理解,比如在题目要去除值为val的元素,除了找到“==”的元素想办法去掉以外,可以选择“!=”的元素,忽略相等的元素;比如本题,移动起始指针比较麻烦,我们可以选择移动终止指针。

要慢慢学会跳脱常规思路,以及细心。

59.螺旋矩阵II

题目链接:螺旋矩阵II

初印象

晕,感觉过程会比较复杂,难以抽象出一个具体的代码。

思路分析

  1. 循环不变量很重要,要有一个统一的处理方法才能接着进行循环,本题采用左闭右开的原则

  2. 一圈为一次循环,n*n矩阵循环n/2全,每循环一圈起点(startX,startY)都会发生变化,因此每一圈都要startX++,startY++,每循环一圈后圈也会变小,因此每一圈都要offset++

    总结:startX和startY控制起点,offset控制循环圈的大小

  3. 奇数矩阵要特别注意

代码

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

心得

思路清晰的话很简单。总感觉过几天自己会忘掉,属于懂了这一题,但是还没学会分析方法。在大脑中模拟一遍循环过程,去寻找循环不变量。

你可能感兴趣的:(算法学习,算法,java)