代码随想录训练营DAY2 | 第一章:数组_Part02 | 题目:977.有序数组的平方 ,209.长度最小的子数组 ,59.螺旋矩阵II

1.59螺旋矩阵II

力扣题目链接

1.题目概述:

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

2.理解题意:

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

穷举题例
不难看出: 5✖️5循环了两圈+一个数,4✖️4循环了两圈,3✖️3循环了1圈+一个数

规律: n✖️n数组,循环n>>1圈,如果n是奇数,还需要加上中间的数字

3.重点:

  1. 这道题的循环体是以圈为单位,圈的个数跟矩阵N有关系;
  2. 同时包含【区间定义】的考察,坚持循环【不变量法则】,按照“上右下左”的顺序依次编写
  3. 变量的定义:
    • 负责控制循环次数的变量;
    • 矩阵数组的下标存储矩阵以及坐标值,可以用来按顺序循环数组内容;
    • 循环的开始点;
    • 数组下标所要代表的具体数值;

4.实现代码:

首先写出大的循环体来:

class Solution {
    public int[][] generateMatrix(int n) {
    // 定义循环次数变量
    int loop = 0;
    //定义起始坐标值
    int start = 0;
    //定义一个空矩阵
    int [][] res =new int[n][n];
    //定义一个填充数字
    int count=1;
    int i=0;
    int j=0;

    //开始循环体
    //使用while循环,循环次数是n>>1,或者说n/2
    while(loop<n/2){

    }
    //循环体写完,立刻过来循环体外,写下这行代码
    if(n%2==1){
        //将最后的值给他
        res[start][start]=count;
    return res;
    }
    }
} 

接下来开始写循环体:

class Solution {
    public int[][] generateMatrix(int n) {
    // 定义循环次数变量
    int loop = 0;
    //定义起始坐标值
    int start = 0;
    //定义一个空矩阵,注意语法问题
    int [][] res =new int[n][n];
    //定义填充数字,修改count=1
    int count=1;
    //再定义一个i
    int i=0;
    int j=0;
    //开始循环体
    //使用while循环,循环次数是n>>1,或者说n/2
    //判断边界后,loop从1开始
    while(loop++<n/2){
        //先写上(从左到右)注意左闭右开
        //起始:想象着从(i,j)开始,先是保持(i)不变,(j)坐标循环
        // (j)循环遵循区间不变为左闭右开,左边等于j=start,右边小于n-1
        //终止:n-1草率了,还要考虑第二圈,第三圈,所以n-loop(第一遍不要求写出来)
        for(j=start;j<n-loop;j++){
            //例如:loop=5 (0,1)(0,2)(0,3)(0,4),嗯,这是我们需要输出的数组
            //填充的内容就是1,2,3,4呗
            res[start][j]=count++;
        }
        //第二个,for是右(从上到下)注意上闭下开
        for(i=start;i<n-loop;i++){
            //例如:loop=5 (0,4)(1,4)(2,4)(3,4)(4,4)
            //j=n-loop=5-1=4(自动继承上一个for循环)
            res[i][j]=count++;
        }
        //从右到左,右闭左开
        //i=n-loop=4,j=4
        //j从4减少到1
        for(;j>=loop;j--){
            //填充:9 10 11 12
            res[i][j]=count++;
        }
        //最后,从下到上
        for(;i>=loop;i--){
            res[i][j]=count++;
        }
        //别漏了,每一圈来讲start++
        start++;
        }
        if(n %2 ==1){
        //将中间的值还给他
        res[start][start]=count;
        } 
    return res;
    }
}

2. 209长度最小的子数组

力扣题目链接

1.题目概述:

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

2.理解题意:

输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。

3.重点:

  1. 暴力解决(双for循环大开大合):
    概述:一个边界正常往前推进,一个边界以上一个边界为前提,往前推进(这就能囊括所有的子数组情况了)一边推进还一边做比较,不断刷新最小值,推出符合题意的结果
    • 利用【两个】for循环构建【子数组】, i 以【0】为起点, j 以【i】为起点 卡出子数组长度;
    • 变量安排:【sum】窗口元素的和;【subLength】当前窗口的长度;【result】最终结果长度;
  2. 窗口解决(双指针物尽其用):
    概述:利用两个指针构建一个滑动窗口,右边界自然前进,窗口其大小一旦满足条件(>=s)则左边界收缩。并以此构建循环体并筛选出最短的来符合题意。
    - 利用【一个】for循环的【右边界】加权出sum,再利用【左边界】收缩来选长度最小的;
    - 核心代码:sum-=nums[left++] 结合之前sum+=nums[right];理解
    - 变量安排:【sum】窗口元素的和;【subLength】当前窗口的长度;【result】最终结果长度;

4.实现代码:

1. 暴力法(双for)
class Solution {
    public int minSubArrayLen(int target, int[] nums) {
//暴力法简介:一个边界正常往前推进,一个边界以上一个边界为前提,
//往前推进(这就能囊括所有的情况了)一边推进还一边做比较,不断刷新,推出符合题意的结果
    int result = Integer.MAX_VALUE;//注意语法,全是大写
    int sum=0;
    int subLength=0;
    for(int i=0;i<nums.length;i++){
        sum=0;//
        for(int j=i;j<nums.length;j++){
            sum+=nums[j];
            if(sum>=target){
            //子序列长度
                subLength=j-i+1;
                result=result<subLength? result:subLength;
                break;
            }
        }
    }
    return result == Integer.MAX_VALUE? 0:result;
    }
}
2.窗口法(双指针)
class Solution {
    public int minSubArrayLen(int target, int[] nums) {
    int left=0;
    int sum=0;
    int result=Integer.MAX_VALUE;//注意这里语法知识点
    for(int right=0;right<nums.length;right++){
        sum+=nums[right];
        while(sum>=target){
            int subLength=right-left+1;
            result=Math.min(result,subLength);
            sum-=nums[left++];//精华
        }
    }
    return result == Integer.MAX_VALUE?0:result;
    }
}

3. 977 长度最小的子数组

力扣题目链接

1.题目概述:

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

2.理解题意:

输入:nums = [-4,-1,0,3,10]
输出:[0,1,9,16,100]
解释:平方后,数组变为 [16,1,0,9,100]
排序后,数组变为 [0,1,9,16,100]

规律: 最大的数一定是在两侧
解决思路:搞个双指针,逐渐向中间合龙,新数组由大到小更新比较好

3.重点:

  1. 核心循环体:while(left<=right) 总能遍历整个数组(这里的数组都是递增顺序数组)
    • 【left】=0 ; 【right】=length-1
  2. 核心代码:int index = result.length - 1; result[index–] = nums[left] * nums[left];
    • 新数组的下标由大到小更新
  3. 变量设计:左右边界(指针)、储存结果的数组(数组大小的初始化)、新数组下标

4.代码实现:

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]) {
                // 正数的相对位置是不变的, 需要调整的是负数平方后的相对位置
                //指针的挪动在这里很奇妙
                //新数组的index在每次确定一个值就要挪一下
                result[index--] = nums[left] * nums[left];
                ++left;
                /*
                在里个例子中,++l和l++的效果是一样的,因为它们的作用是将l的值加1。
                在这种情况下,两者的区别不大。但是,在一些其他的情况下,++l和l++的
                效果是不同的。
                */
            } else {
                result[index--] = nums[right] * nums[right];
                --right;
            }
        }
        return result;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值