力扣刷题之数组(2) | 977. 有序数组的平方、209. 长度最小的子数组、59. 螺旋矩阵II

Leetcode 977. 有序数组的平方

题目链接

思路

这道题的意思很简单,暴力解法很容易想到,直接平方再排序。但是由于时间复杂度过高,我们可以采用双指针的解法。

由于题目中强调数组是非递减顺序排序的, 但考虑到负数平方之后可能成为最大数。所以我们这里的双指针,一个从后向前遍历,一个从前向后遍历

难点

数组平方的最大值就在数组的两端,不是最左边就是最右边,此时定义两个指针分别为i,j;由i,j指向的元素判断大小,得到新的数组元素的排序。
下面有动画帮助大家理解。
在这里插入图片描述

代码(Java)

写法1:暴力解法

时间复杂度: 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;
    }
}

写法2:双指针法

时间复杂度:O(n)

class Solution {
    public int[] sortedSquares(int[] nums) {
       int i=0; //前指针i,从前往后遍历
       int j=nums.length-1;//后指针j,从后往前遍历
       int[] ret=new int[nums.length];//定义新数组
       int k=nums.length-1;//新数组的指针,指向元素存放的位置
       while (i<=j){
           if (nums[i]*nums[i]>nums[j]*nums[j]){ //负数的绝对值大于正数的绝对值
               ret[k--]=nums[i]*nums[i];
               i++;
           }else { //负数的绝对值小于or等于正数的绝对值
               ret[k--]=nums[j]*nums[j];
               j--;
           }
       }
       return ret; 
    }
}

代码随想录链接

下面是代码随想录的文章链接与视频链接,帮助大家更好地理解这道题。
文章
视频

Leetcode 209. 长度最小的子数组

题目链接

思路

可以采用暴力解法,两层for循环嵌套,一层for循环用来控制数组的起始位置,另一层for循环控制数组的终止位置
两个for循环,也可以用双指针法来解决,分别用两个指针和一个for循环完成。

难点

这道题是一道典型的滑动窗口问题,使用一个for循环时,我们首先确定次循环确定的是数组的起始位置还是终止位置
如果用来确定起始位置,那么数组的终止位置还是无法确定。
如果用来确定终止位置,那么该指针即用来遍历数组中的元素,当窗口中的元素和 大于目标值时,移动前指针进行窗口的缩小,从而得到满足条件的窗口长度最小值。
下面用动画来帮助大家理解。
在这里插入图片描述

代码(Java)

写法1:暴力解法

时间复杂度:O(n^2)
空间复杂度:O(1)

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int sum;
        int subLen=0;
        int ans= Integer.MAX_VALUE;
        for (int i=0;i<nums.length;i++){//外层循环:确定数组的起始位置
            sum=0;
            for (int j=i;j<nums.length;j++){//内层循环:确定数组的终止位置
                sum+=nums[j];
                if (sum>=target){
                    subLen=j-i+1;
                    ans = Math.min(subLen,ans);
                    break;
                }
            }
        }
        return ans == Integer.MAX_VALUE ? 0:ans;
    }
}

写法2:双指针法

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

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int i=0;//前指针i,用来确定滑动窗口的起始位置
        int sum=0;
        int subLen=0;
        int ans=Integer.MAX_VALUE;
        for (int j=0;j<nums.length;j++){ //后指针j,用来确定滑动窗口的终止位置
            sum+=nums[j];
            while (sum>=target){
                subLen=j-i+1;
                ans=Math.min(subLen,ans);
                sum-=nums[i];
                i++; //滑动窗口:更新i的位置
            }
        }
        return ans == Integer.MAX_VALUE ? 0:ans;
    }
}
    }
}

代码随想录链接

下面是代码随想录的文章链接与视频链接,帮助大家更好地理解这道题。
文章
视频

Leetcode 59. 螺旋矩阵II

题目链接

思路

这道题本身没有强调技术性的算法,需要搞清楚的只有每次读取螺旋矩阵的元素的方法,顺时针读取矩阵中的元素时,每层可以看作四条边。

由于每次读取的起始位置都是正方形的左上角,观察可得横纵坐标相同,即在二维数组中的两个索引数相同

循环次数,根据观察得到等于n/2。当n为奇数时,中间的数需要再单独补上。

难点

四条边的读取方向可以分为:

  • 从左到右➡️
  • 从上到下⬇️
  • 从右到左⬅️
  • 从下到上⬆️

读取每层循环时,如果无规则地读取,很容易扰乱思绪。所以必须要确定边界位置读不读,这里我采用取头舍尾的读法。

代码(Java)

class Solution {
    public int[][] generateMatrix(int n) {
        int ret[][]=new int[n][n];
        int start=0;//读取螺旋矩阵的起始位置
        int count=1;//读取到的数字(从1开始依次向后)
        int loop=0;//控制循环的次数
        int i,j;
        while (loop++ < n/2){
            //从左到右,此时的纵坐标是统一的,即前索引
            for (j=start;j<n-loop;j++){
                ret[start][j]=count++;
            }
            //从上到下,此时的横坐标是统一的,即后索引
            for (i=start;i<n-loop;i++){
                ret[i][j]=count++;
            }
            //从右到左,此时的纵坐标是统一的,即后索引
            for (;j>=loop;j--){
                ret[i][j]=count++;
            }
            //从下到上,此时的横坐标是统一的,即后索引
            for (;i>=loop;i--){
                ret[i][j]=count++;
            }
            start++;
        }
        if (n%2==1){
            ret[start][start]=n*n;
        }
        return ret;
    }
}

代码随想录链接

下面是代码随想录的文章链接与视频链接,帮助大家更好地理解这道题。
文章
视频

总结

今天主要学习了双指针的解法,此解法在数组的算法题中经常用到,该解法最重要的点在于两个指针分别的任务是什么,另外螺旋矩阵问题和二分法问题类似,问题的重点都在于确定循环不变量左闭右闭左闭右开,区间的不同也会导致循环不变量的定义不同。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Fuego91

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值