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

101 阅读4分钟

977.有序数组的平方

题目:给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。

977. 有序数组的平方 - 力扣(Leetcode)

思路: 在非递减数列中可能存在负数,绝对值大的负数在平方后数值也大,使平方后的数列可能不是一个非递减的数列。
暴力解法:

  1. 遍历数组,并原地对每个数组元素进行平方o(n)o(n)
  2. 使用java的工具类对数组进行排序。o(n2)o(n^2)

双指针法: 将数组元素都进行平方后,数组的单调性是先单调递减后单调递增的(原数组全为正数或全为负数也符合这种情况,只是递减或递增的部分长度为0)。 根据这个规律,所求数组的最大值从原数组的两端取得。因此,可以从原数组的两端出发进行遍历,不断比较两端指针指向元素的绝对值,并将较大值平方后记录到目标数组中。
时间复杂度:o(n)o(n)
空间复杂度:o(n)o(n)

class Solution {
    public int[] sortedSquares(int[] nums) {
        int[] result=new int[nums.length];

        int slow=0,high=nums.length-1;
        for(int i=result.length-1;i>=0;i--){
            if(Math.abs(nums[slow])>Math.abs(nums[high])){
                result[i]=nums[slow]*nums[slow];
                slow++;
            }else{
                result[i]=nums[high]*nums[high];
                high--;
            }
        }
        
        return result;
    }
}

209. 长度最小的子数组

题目:给定一个含有 n 个正整数的数组和一个正整数 target。 找出该数组中满足其和 target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。

209. 长度最小的子数组 - 力扣(Leetcode)

思路:
题目中要求连续子数组,因此可以使用滑动窗口,窗口内的数组元素为组成连续子数组的元素。
对原数组进行遍历,使用total记录当前窗口元素的和,使用min记录题目所求的连续子数组的最小长度。
对于每一个数组元素,首先移入到窗口中,再判断新的total是否≥target,当total>=target条件满足时,不断重复以下操作:
判断total-窗口第一个元素>=target是否满足,若满足,移除窗口第一个元素,并更新total,并重复此过程,否则,从min和当前窗口长度中取较小者更新min,并结束这一轮操作。

时间复杂度:o(n)o(n)

示意图如下:

长度最小的子数组-滑动窗口.jpg

  • 按照思路,窗口具有先进先出的特性,可以使用一个队列维持滑动窗口。
class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        Deque<Integer> window =new LinkedList<>();

        Integer min=Integer.MAX_VALUE;
        int total=0;

        for(int i=0;i<nums.length;i++){
            window.add(nums[i]);
            total+=nums[i];
            while(total>=target){
                if(total-window.peek()>=target){
                    total-=window.poll();
                }else{
                    min=min>window.size()?window.size():min;
                    break;
                }
            }
        }

        return min==Integer.MAX_VALUE?0:min;

    }
}
  • 由于窗口所维持的子数组是原数组中的连续的几个数组元素,可以通过维护窗口第一个元素和最后一个元素的下标,从而维护当前窗口,而无需要额外的内存空间。
class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        
        int start=0,end=0;
        int total=0;
        int min=Integer.MAX_VALUE;

        while(end<nums.length){
            total+=nums[end];
            while(total>=target){
                if(total-nums[start]>=target){
                    total-=nums[start];
                    start++;
                }else{
                    min=min>(end-start+1)?(end-start+1):min;
                    break;
                }
            }
            end++;
        }

        return min==Integer.MAX_VALUE?0:min;
    }
}

59.螺旋矩阵

题目:给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。

59. 螺旋矩阵 II - 力扣(Leetcode)

思路:
这道题解题的关键在于遍历的区间范围,将二维矩阵从外到里一圈一圈地进行遍历,每一圈的遍历分为四段,依次是从左到右从上到下从右到左从下到上
每完成一圈遍历,遍历的范围就向内收缩一圈,即给每一个遍历段的起点和终点都收缩一格,这种收缩表现为偏移对起点的偏移,使用offset表示偏移量。
offset=n/2offset=\lfloor n/2 \rfloor时,

  1. nn为偶数时,左右、上下方向的偏移量加起来都为nn,这意味着矩阵遍历完成;
  2. nn为奇数时,左右、上下方向的偏移量加起来都为n1n-1,此时,只有nums[n/2][n/2],即矩阵最中心的位置还未遍历,而这个值是遍历中最后一个值,即n2n^2,将这个值填入矩阵最中心的位置,即可结束遍历。

示意图如下:

螺旋矩阵II.jpg

class Solution {
    public int[][] generateMatrix(int n) {
        int num=1;
        int[][] res=new int[n][n];

        for(int offset=0;offset<n/2;offset++){

            //left->right
            //i:offset
            //j:offset->n-offset-2
            for(int j=offset;j<=n-offset-2;j++){
                res[offset][j]=num++;
            }

            //up->down:
            //j:n-offset-1
            //i:offset->n-offset-2
            for(int i=offset;i<=n-offset-2;i++){
                res[i][n-offset-1]=num++;
            }

            //right->left
            // i:n-offset-1
            // j:n-offset-1 -> offset+1
            for(int j=n-offset-1;j>=offset+1;j--){
                res[n-offset-1][j]=num++;
            }

            // down -> up
            // j:offset
            // i:n-offset-1 -> offset+1
            for(int i=n-offset-1;i>=offset+1;i--){
                res[i][offset]=num++;
            }
        }

        if(n%2!=0){
            res[n/2][n/2]=n*n;
        }

        return res;
    }
}