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

977.有序数组的平方

题目

力扣题目链接(opens new window)

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

示例 1:

  • 输入:nums = [-4,-1,0,3,10]

  • 输出:[0,1,9,16,100]

  • 解释:平方后,数组变为 [16,1,0,9,100],排序后,数组变为 [0,1,9,16,100]

示例 2:

  • 输入:nums = [-7,-3,2,3,11]

  • 输出:[4,9,9,49,121]

思路

如果数组没有包含负数,那么递增的数组[0,3,10],平方后,数组仍然还是递增 [0,9,100]

但是这里包含了负数,所以平方后,最大值出现在最左边或者最右边,不可能出现在中间;

由此可以使用双指针算法。left=0;right=nums.length-1;比较平方后的值,放在新数组的最后位置。然后向中间移动指针。

代码

class Solution {
    public int[] sortedSquares(int[] nums) {
        int left = 0;
        int right = nums.length - 1; // 使用闭区间,left==right有意义
​
        int[] newNums = new int[nums.length];
        int lastIndex = newNums.length - 1;
​
        while (left <= right) {
            int leftSq = nums[left] * nums[left];
            int rightSq = nums[right] * nums[right];
            // 比较平方最大值
            if (leftSq > rightSq) {
                newNums[lastIndex] = leftSq;
                lastIndex--; // 新数组最大值向后走
                left++; // 左指针中间走
            } else {
                newNums[lastIndex] = rightSq;
                lastIndex--;
                right--;
            }
        }
        return newNums;
    }
}

209.长度最小的子数组

题目

力扣题目链接(opens new window)

给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。

示例:

  • 输入:s = 7, nums = [2,3,1,2,4,3]

  • 输出:2

  • 解释:子数组 [4,3] 是该条件下的长度最小的子数组。

提示:

  • 1 <= target <= 10^9

  • 1 <= nums.length <= 10^5

  • 1 <= nums[i] <= 10^5

思路

我想到的思路是用滑动窗口。

详细解释:
  1. 初始化变量

    • result 用于存储最短的子数组长度,初始值为 Integer.MAX_VALUE,方便后续比较和更新。

    • sum 用于存储当前窗口内所有元素的和。

    • i 是滑动窗口的起始位置。

    • subLength 用于存储当前窗口的长度。

  2. 遍历数组

    • 使用 for 循环遍历数组,其中 j 表示滑动窗口的结束位置。

  3. 更新窗口和

    • 每次循环将 nums[j] 加到 sum 中,更新窗口内的和。

  4. 缩小窗口

    • sum 大于或等于 target 时,进入 while 循环尝试缩小窗口。

    • 计算当前窗口长度,并更新 result 为更小的值。

    • sum 中减去 nums[i],并将起始位置 i 右移,缩小窗口。

  5. 返回结果

    • 如果 result 仍为 Integer.MAX_VALUE,说明没有找到符合条件的子数组,返回0。

    • 否则,返回 result,即最短的子数组长度。

这个版本的代码逻辑清晰,注释详细,便于理解和维护。

代码

我觉得好理解的版本
class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int result = Integer.MAX_VALUE; // 初始化结果为最大值,以便后续比较
        int sum = 0; // 初始化滑动窗口内元素之和为0
        int i = 0; // 初始化滑动窗口的起始位置
        int subLength = 0; // 初始化滑动窗口的长度
​
        // 遍历数组,j 表示滑动窗口的结束位置
        for (int j = 0; j < nums.length; j++) {
            // 增加窗口的右边界,并更新窗口内元素之和
            sum += nums[j];
​
            // 当窗口内元素之和大于等于目标值时,开始尝试缩小窗口
            while (sum >= target) {
                // 计算当前窗口长度
                subLength = j - i + 1;
                // 更新最短长度
                result = Math.min(result, subLength);
                // 缩小窗口,移除左边界的元素,并将起始位置右移
                sum -= nums[i];
                i++;
            }
        }
        // 如果结果未更新,则返回0;否则返回最短长度
        return result == Integer.MAX_VALUE ? 0 : result;
    }
}
版本1
class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        // 初始化窗口双指针:left 指向窗口左边界,right 指向窗口右边界
        int left = 0;
        int right = 0;
        
        // 初始化返回结果,将其设置为一个较大的值以便后续比较
        int res = Integer.MAX_VALUE;
        
        // 初始化子数组的和为0
        int sum = 0;
​
        // 开始滑动窗口,当右边界未越界时
        while (right < nums.length) {
            // 先将当前右边界的值加到 sum 中
            sum += nums[right];
​
            // 尝试缩小窗口
            while (sum >= target) {
                // 计算当前窗口长度 ,注right - left + 1是个数学问题
                int subLength = right - left + 1;
                // 更新结果,选择更小的长度
                res = Math.min(res, subLength);
​
                // 移动左边界,同时减去左边界值从 sum 中
                sum -= nums[left];
                left++;
            }
​
            // 移动右边界,继续扩展窗口
            right++;
        }
​
        // 如果 res 没有更新,说明没有符合条件的子数组,返回0
        return res == Integer.MAX_VALUE ? 0 : res;
    }
}

59.螺旋矩阵II

题目

力扣题目链接(opens new window)

给定一个正整数 n,生成一个包含 1 到 n^2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。

示例:

输入: 3 输出: [ [ 1, 2, 3 ], [ 8, 9, 4 ], [ 7, 6, 5 ] ]

思路

那么我按照左闭右开的原则,来画一圈,大家看一下:

这里每一种颜色,代表一条边,我们遍历的长度,可以看出每一个拐角处的处理规则,拐角处让给新的一条边来继续画。

代码

class Solution {
    public int[][] generateMatrix(int n) {
        // 初始化偏移量,用于调整每圈的边界
        int offset = 1;
        // 初始化起始位置坐标
        int startX = 0;
        int startY = 0;
        // 初始化计数器,从1开始填充矩阵
        int count = 1;
        // 计算需要迭代的圈数
        int loop = n / 2;
        // 计算矩阵中间的位置,用于处理奇数维度的情况
        int mid = n / 2;
        // 定义结果矩阵
        int[][] nums = new int[n][n];
​
        // 迭代每一圈
        while (loop > 0) {
            // 从左到右填充当前圈的上边
            for (int j = startY; j < n - offset; j++) {
                nums[startX][j] = count++;
            }
            // 从上到下填充当前圈的右边
            for (int i = startX; i < n - offset; i++) {
                nums[i][n - offset] = count++;
            }
            // 从右到左填充当前圈的下边
            for (int j = n - offset; j > startY; j--) {
                nums[n - offset][j] = count++;
            }
            // 从下到上填充当前圈的左边
            for (int i = n - offset; i > startX; i--) {
                nums[i][startY] = count++;
            }
​
            // 更新起始位置,向内缩一圈
            startX++;
            startY++;
            // 增加偏移量
            offset++;
            // 减少圈数
            loop--;
        }
​
        // 如果 n 是奇数,单独填充矩阵的中心位置
        if (n % 2 != 0) {
            nums[mid][mid] = count;
        }
​
        // 返回填充完毕的矩阵
        return nums;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值