代码随想录训练营D2-数组篇 day2| 977 有序数组的平方、209 长度最小的子数组 、59.螺旋矩阵II

代码随想录训练营D2-数组篇 day2| 977 有序数组的平方、209 长度最小的子数组 、59.螺旋矩阵II

(一) 977 有序数组的平方

题目链接
文章链接
视频讲解

1. 思路

1.1 直观思路

	循环一遍,在原数组中将元素平方并放回原处。使用Arrays.sort(),将数组由小到大排序。

1.2 代码随想录思路

	应用双指针思想。
	由于原数组是有序的,从小到大。如果有正、有负,那么在平方完之后,数组呈两边大,中间小的状态。
	可以在数组头尾分别设置一个指针,两指针向中间逼近,两个指针对应元素的平方进行比较,较大的元素的平方存入新数组。由于新数组要求也是从小到大,所以可以从后向前存入新数组中。指针所指元素进新数组,那么指针也移动一格(前面的指针向后一格,后面的指针向前一格)

2. 代码


public class Q977SortedSquares {
    //给你一个按 非递减顺序 排序的整数数组 nums,
    //返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
    class Solution {
        public int[] sortedSquares(int[] nums) {
            int len = nums.length;
            for(int i = 0; i < len; ++i){
                nums[i] *= nums[i];
            }
            Arrays.sort(nums);
            return nums;
        }

        //双指针。
        //由于原本数组是有序的,在平方之后,数组中元素分布是两边大中间小。
        //可以设置两个指针分别在开头和结尾的位置,每次都选择当前剩余数组中最大的元素放到新数组中
        //大 <--- 小 ----> 大
        //^               ^
        //p               q     两个指针依次向中间逼近
        //新数组也是从小到大排列的,所以填充新数组时 要从后向前填充。
        public int[] sortedSquares1(int[] nums) {
            int len = nums.length;
            int[] result = new int[len];

            //计算平方 以及 排序 可以同时进行
            int index = len - 1;
            for(int p = 0, q = len -1; p <= q;){
                //在两指针处,选择较大的,在新数组中从后向前填充
                if(nums[p] * nums[p] >= nums[q] * nums[q]){
                    //为新数组赋值,并且p后移
                    result[index--] = nums[p] * nums[p];
                    ++p;
                }else {
                    //为新数组赋值,并且q前移
                    result[index--] = nums[q] * nums[q];
                    --q;
                }
            }
            return result;
        }
    }
}

3. 实现过程中的问题

(二) 209.长度最小的子数组

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

题目链接
文章链接
视频讲解

1. 思路

1 双层for循环,遍历出所有的子数组,并随时更新最小子数组。

2 双指针,这里也叫滑动窗口。2个指针。

因为要找的子数组是连续的,所以可以用一个前后都可以伸缩的框来挑出最小子数组。
起始时,框的左右两端都指向下标0处元素。框的右侧先行,整个框不断变大,变量sum要累加框中的元素,直到sum>=target, 此时框中的算是疑似长度最小子数组(没遍历完不能确定谁最小),所以更新最小子数组长度min;
这时看看框的长度能否更小,所以将框的左侧向右压,若还满足sum>=target,则更新min,直到sum <target就不压了,转而右移框的右侧,筛选其他可能的子数组。

2. 代码

public int minSubArrayLen(int target, int[] nums) {
    int left = 0;
     int sum = 0;
     int min = Integer.MAX_VALUE;//>=target 的最小子数组的长度

     for(int right = 0; right < nums.length; ++right){
         //每一轮for循环 代表右侧又新加了一个元素,先更新sum
         sum += nums[right];

         //sum >= target ,先更新min,再不断!收缩左侧
         while(sum >= target){//!!!这里不需要 left <= right
             min = Math.min(right - left + 1, min);
             //左侧收缩,并更新sum
             sum -= nums[left++];
         }

         //sum < target 右侧向右拓宽,即进入下一轮for循环
     }
     //若min从来没有更新过,则返回0
     return min == Integer.MAX_VALUE ? 0 : min;
}

3. 实现过程中的问题

//为什么while中不需要呢  && left <= right
while(sum >= target){
    min = Math.min(right - left + 1, min);
    //左侧收缩,并更新sum
    sum -= nums[left++];
}

思考极限情况left一直++,直到与right相遇在同一位置。
在这里插入图片描述
所以极限时也不会出问题。

(三) 59.螺旋矩阵II

题目建议: 本题关键还是在转圈的逻辑,以及二分搜索中提到的区间定义(左闭右闭、左闭右开,选择了一种后 从前到后就要一致)。

题目链接
文章链接
视频讲解

0.题目

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

在这里插入图片描述
输入:n = 3
输出:[[1,2,3],[8,9,4],[7,6,5]]

1. 思路

1.1 我狄思路

1.创建nxn二维数组,遍历1-n^2并填充至二维数组
2.分类讨论:
i横向下标,j纵向下标
随着数字不断地填充,横纵坐标所能走到的最小、最大值都会发生变化。
iMax:横坐标所能达到的最大值。其他同理。

(以下- - iMax 均显示为–iMax)
1)向右侧走时。先++iMin,++j(考虑走第二圈时,要先向右,因为原地的位置已经填好值了),按顺序向右填充(i值不变,j不断增大),直到j达到最大值jMax时,则要向下填充。
2)向下填充时。先–jMax,++i(i+1 即向下串一个位置),按顺序向下填充(j不变,i增大),直到达到i最大值iMax,开始向左填充。
3)向左侧走时。先–iMax,–j(j-1 即j向左串一个位置) 按顺序向左填充(i不变,j不断变小),直到j达到最小值jMin时,则要向上填充。
4)向上填充时。先++jMin,–i(i-1 向上串一个位置)按顺序向上填充(j不变,i不断变小),直到达到i最小值iMin,开始向右填充。

直到填充至n^2

1.2 代码随想录思路

整体也是分为四步:左->右,上->下,右->左,下->上。
只是while循环中条件改为判断需要走几圈(一圈包括上面四步)。
(n = 2时,一圈;n = 4时,两圈;n为偶数时,刚好整数圈走完;
n = 3时,一圈 + 填充最中间的元素;n为奇数时, 须最后补充)
区间定义的一致性体现在,每一步中都是左闭右开。
即,第一步,左->右,填充A而不填充B;第二步 上->下,填充B而不填充C…
在这里插入图片描述
在这里插入图片描述

2. 代码


 public int[][] generateMatrix(int n) {
    int[][] result = new int[n][n];

    int iMin = 0, jMin = 0, iMax = n - 1, jMax = n - 1;
    int cur = 1;//待填入数组中的数值
    int i = 0, j = -1;//工作下标
    while(cur <= n * n){
/*
i横向下标,j纵向下标
1)向右侧走时。先++iMin,按顺序向右填充(i值不变,j不断增大),直到j达到最大值jMax时,则要向下填充。
2)向下填充时。先--jMax,按顺序向下填充(j不变,++i),直到达到i最大值iMax,开始向左填充。
3)向左侧走时。先--iMax,按顺序向左填充(i不变,--j),直到j达到最小值jMin时,则要向上填充。
4)向上填充时。先++jMin,按顺序向上填充(j不变,--i),直到达到i最大值iMin,开始向右填充。
直到填充至n^2
* */
        ++iMin;
        while (j < iMax){
            result[i][++j] = cur++;
        }

        --jMax;
        while(i < iMax){
            result[++i][j] = cur++;
        }

        --iMax;
        while(j > jMin){
            result[i][--j] = cur++;
        }

        ++jMin;
        while (i > iMin){
            result[--i][j] = cur++;
        }
    }
    return result;

}

 /**n值   圈数
*  1    0圈 & 在最终间填上数1
 *  2    1圈
 *  3    1圈 & 在最终间填上数9
 *  4    2圈
 */

public int[][] generateMatrix1(int n) {
    int[][] result = new int[n][n];

    int x = 0, y = 0;//下标
    int offset = 0;//约等于 现在是第几圈。用于限制坐标范围,循环完一圈 就++
    int cur = 1;//待填入数组中的数值


    //无论是奇偶,都先走n/2圈
    while(offset++ < n/2){
        //以下四步 每步都是左闭右开

        //左-->右
        while(y < n - offset){
            result[x][y++] = cur++;
        }

        while(x < n - offset){
            result[x++][y] = cur++;
        }

        while(y > offset - 1){
            result[x][y--] = cur++;
        }

        while(x > offset - 1){
            result[x--][y] = cur++;
        }
        x++;//此为下一圈的起始位置
        y++;
    }

    //n为奇数时,最终间补一个值
    if(n % 2 == 1){
        result[x][x] = cur;
    }
    return result;

}

3. 实现过程中的问题

边界问题。最终是debug de好的边界。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值