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

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

今天的题目难度有所增加 只有有序数组的平方一题自己独立做了出来 其余都看了视频 需要多看多新

有序数组的平方

题目链接

思路

这个还是不难的 关键还是要能想到最大的值无非就是出现在数组的两个边界 要不就是负数很负 要不就是正数很正 不难想到要用双指针的方法 一个指向左边界 一个指向右边界 然后比较二者平方的大小 将大的留在新数组的最右侧(因为题目要求以递增的顺序)然后将大的一侧的边界挪动一位 继续比较

代码

class Solution {
    public int[] sortedSquares(int[] nums) {
        int []result = new int[nums.length];
        int left =0;
        int right = nums.length -1;
        int size = nums.length-1; //给result数组用的 从大到小
        while(left<=right){//left是可以等于right的 指向同一个元素
            int leftSquare = nums[left]*nums[left];
            int rightSquare = nums[right]*nums[right];
            if(leftSquare<rightSquare){
                result[size] = rightSquare;
                right--;
                size--;
            }
            else{
                result[size] = leftSquare;
                left++;
                size--;
            }
        }
        return result;
    }
}

时间复杂度O(n) 空间复杂度O(n)

长度最小的子数组

题目链接

思路

这道题用到的一个关键是滑动窗口 其实滑动窗口的实际实现还是双指针 只不过不像原先我们用的是双指针指的元素 滑动窗口利用的是二者指针之间的值 关键还是在于我们要明确什么时候双指针要移动 该怎么移动

此题用的是同向的双指针 将末尾指针每次移动一个单位 直到窗口中的和达到了target 可以这么理解:初始你有0个苹果 一个机器随机的送出苹果 而你的目标是达到10个苹果 经过了几轮后 你达到了这个目标 但是有可能最后一次给你了100个苹果 那么前几轮对你来说都是没用的 因此我们需要一轮轮的丢弃前几轮的苹果 看至少需要几轮能达到目标

代码

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) {//不断相加达到target
                result = Math.min(result, right - left + 1); //二者之间取最小值
                sum -= nums[left];//每次丢弃一轮的🌿
                left++}
        }
        return result == Integer.MAX_VALUE ? 0 : result; //如果一直没有达到target 则返回0
    }
}

这里为什么要用while:就例如我上面的例子 我们需要一轮轮的丢弃 如果只是用了一个if 那么我们只丢弃了一轮 找不到最小的子数组(例如 1,1,1,1,100 target=100)

时间复杂度O(n) 空间复杂度O(1)

Tips

这道题有使用条件就是数组中不能有负值 如果出现负值 我们窗口的值就不能保证简单的缩小即减小 扩张即扩大

螺旋矩阵

这道题相对来说复杂不少 需要明确边界的判断 也需要明确每一次loop哪些发生了变化

思路

求解本题依然是要坚持循环不变量原则 每一条边坚持一个区间 不要一会左闭右开 一会左闭右闭 这样边界一会就搞晕了

img

模拟顺时针画矩阵的过程:

  • 填充上行从左到右
  • 填充右列从上到下
  • 填充下行从右到左
  • 填充左列从下到上

由外向内一圈一圈这么画下去。

我的想法是对于一个n=4的二维数组 遍历一个loop后相当于我们还剩一个n=2的二维数组需要再走一圈(这也是为什么loop=n/2) 而对于n为奇数的情况呢 我们最终都会剩下一个最中心的块 单独判断一下即可

同时我们可以设置每一个loop的起点 比如第一个loop的起点是(0,0)第二次就变成(1,1)第三次变成(2,2)以此类推

代码

class Solution {
    public int[][] generateMatrix(int n) {
        int [][]result = new int[n][n];
        int value=1;
        int start= 0; //起点的位置 每次转一圈之后起点都会变化 例如(0,0)->(1,1)
        int offset=1; //每次移动的距离 初始是1
        int loop=0; //代表转了几圈
        int i,j;
        while(loop<n/2){
            for(j =start;j<n-offset;j++){
                result[start][j]=value;
                value++;
            }
            for (i =start;i<n-offset;i++){
                result[i][j] = value;
                value++;
            }
            for (;j>start;j--){
                result[i][j]=value;
                value++;
            }
            for (;i>start;i--){
                result[i][j]=value;
                value++;
            }
            start++;
            offset++;
            loop++;
        }
        if(n % 2 != 0){//判断n为奇数的情况
            result[n/2][n/2]=n*n;
        }
        return result;
    }
}

四个循环代表四条边 代码中其实有不少小细节:

  1. 对于一条边 由于我采用的是左闭右开的区间 这一条边的边界点我是不处理的 交给下一个循环 而同时我们的循环参数就正好移动到了这个边界的一个横坐标/纵坐标 供我们下一个循环使用 因为下一个循环总有一个值是保持不变的
  2. 有关于这里的offset :因为是左闭右开 右边取不到 所以我们不能简单的i<n 而是要减去一个偏移量 第一次loop减1即可 第二次呢?可以想象这次我们相当于最右边又被剔除掉一个元素(因为已经赋值过了) 那第二次就该减去2了 相当于往里面缩了一格
  3. 后两个循环采用的是i>start 这是因为我们后两条边正好要到的位置就是起点的横坐标/纵坐标 并且同样适用于当我们的起点变化

总结

img
图片取自代码随想录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值