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

977.有序数组的平方

题目建议: 本题关键在于理解双指针思想

题目链接:https://leetcode.cn/problems/squares-of-a-sorted-array/

文章讲解:https://programmercarl.com/0977.%E6%9C%89%E5%BA%8F%E6%95%B0%E7%BB%84%E7%9A%84%E5%B9%B3%E6%96%B9.html

视频讲解: https://www.bilibili.com/video/BV1QB4y1D7ep

思路想法:1)非递减排好的数组,则非负数部分直接返回数字平方值就为非递减顺序

2)负数部分,由于也是按非递减排列,则直接平方后为非递增顺序

3)需要考虑,将负数部分的平方插入到非负数平方返回后的数组中合适位置

然而写不出来.....

暴力:

第 1 步:一层 for 循环遍历数组,将各元素平方后存入数组,这一步的时间复杂度为 O(n)。

第 2 步:快排,时间复杂度为 O(nlogn)。

总的时间复杂度显然是 O(n + nlogn)

 

class Solution {
    public int[] sortedSquares(int[] nums) {
        for(int i= 0;i< nums.length;i ++){
            nums[i] *=nums[i];
            }
        Arrays.sort(nums);
        return nums;
    }
}

 

双指针

思路:

数组其实是有序的, 只不过负数平方之后可能成为最大数了。

那么数组平方的最大值就在数组的两端,不是最左边就是最右边,不可能是中间。

此时可以考虑双指针法了,i指向起始位置,j指向终止位置。

定义一个新数组result,和A数组一样的大小,让k指向result数组终止位置。

 

看思路自己写,然后调试,code如下:

 

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

 

参考答案:

class Solution {
    public int[] sortedSquares(int[] nums) {
        int right = nums.length - 1;
        int left = 0;
        int[] result = new int[nums.length];
        int index = result.length - 1;
        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;
            }
        }
        return result;
    }
}

学习简洁的代码

class Solution {
    public int[] sortedSquares(int[] nums) {
        int l = 0;
        int r = nums.length - 1;
        int[] res = new int[nums.length];
        int j = nums.length - 1;
        while(l <= r){
            if(nums[l] * nums[l] > nums[r] * nums[r]){
                res[j--] = nums[l] * nums[l++];
            }else{
                res[j--] = nums[r] * nums[r--];
            }
        }
        return res;
    }
}

 

209.长度最小的子数组

题目建议: 本题关键在于理解滑动窗口

题目链接:https://leetcode.cn/problems/minimum-size-subarray-sum/

文章讲解:https://programmercarl.com/0209.%E9%95%BF%E5%BA%A6%E6%9C%80%E5%B0%8F%E7%9A%84%E5%AD%90%E6%95%B0%E7%BB%84.html

视频讲解:https://www.bilibili.com/video/BV1tZ4y1q7XE

思路想法:

滑动窗口,窗口值初始为1,逐渐递增,自左向右滑动,查看窗口内之和是否满足条件

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int win = 1;
        while (win < nums.length + 1){
            for(int l = 0;(l + win -1 ) < nums.length;l ++){
                int r = l + win -1;
                int res = 0;
                while(l <= r){
                    res += nums[l++];
                    if(res >= target){
                        return win;
                    }
                }
        }
        return 0;
    }
}

超时

在本题中实现滑动窗口,主要确定如下三点:

  • 窗口内是什么?
  • 如何移动窗口的起始位置?
  • 如何移动窗口的结束位置?

窗口就是 满足其和 ≥ s 的长度最小的 连续 子数组。

窗口的起始位置如何移动:如果当前窗口的值大于s了,窗口就要向前移动了(也就是该缩小了)。

窗口的结束位置如何移动:窗口的结束位置就是遍历数组的指针,也就是for循环里的索引。

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int res = Integer.MAX_VALUE;
        int left = 0;
        int sum = 0;
        for(int right = 0;right < nums.length;right++){
            sum += nums[right];
            while(sum >= target){
                res = Math.min(res,right - left + 1);
                sum -= nums[left++];
            }
        }
        return res == Integer.MAX_VALUE ? 0 : res;
    }
}
  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

总结:知道大概思路,写不出来=。=

59.螺旋矩阵II

题目建议: 本题关键还是在转圈的逻辑,在二分搜索中提到的区间定义,在这里又用上了。

题目链接:https://leetcode.cn/problems/spiral-matrix-ii/

文章讲解:https://programmercarl.com/0059.%E8%9E%BA%E6%97%8B%E7%9F%A9%E9%98%B5II.html

视频讲解:https://www.bilibili.com/video/BV1SL4y1N7mV/

想法思路:

n行n列,自左向右:第一行为1到n;自上到下:第n列为n到2n-1(n+n-1); 自右向左:第n行为2n-1(n+n-1)到3n-2(n+n-1+n-1);自下到上:第一列为3n-2(n+n-1+n-1)到4n-4(n+n-1+n-1 + n-1-1)

不会

看答案:左闭右开、左闭右开、左闭右开!!!

转n/2圈,

 

class Solution {
    public int[][] generateMatrix(int n) {
        int loop = 0;  // 控制循环次数
        int[][] res = new int[n][n];
        int start = 0;  // 每次循环的开始点(start, start)
        int count = 1;  // 定义填充数字
        int i, j;

        while (loop++ < n / 2) { // 判断边界后,loop从1开始
            // 模拟上侧从左到右
            for (j = start; j < n - loop; j++) {
                res[start][j] = count++;
            }

            // 模拟右侧从上到下
            for (i = start; i < n - loop; i++) {
                res[i][j] = count++;
            }

            // 模拟下侧从右到左
            for (; j >= loop; j--) {
                res[i][j] = count++;
            }

            // 模拟左侧从下到上
            for (; i >= loop; i--) {
                res[i][j] = count++;
            }
            start++;
        }

        if (n % 2 == 1) {
            res[start][start] = count;
        }

        return res;
    }
}

先打个卡,2022年11月18日00:39:31,明天再研究

 

posted @   染醉霜林  阅读(44)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
点击右上角即可分享
微信分享提示