Day2 | 数组基础 977. 有序数组的平方 / 209.长度最小的子数组 / 59. 螺旋矩阵 II

文章介绍了使用双指针和滑动窗口解决LeetCode中的几道问题,包括有序数组的平方、长度最小的子数组和螺旋矩阵的生成。通过不同题目的解题过程,强调了双指针法和滑动窗口在处理数组问题中的应用,以及注意点和时间复杂度分析。
摘要由CSDN通过智能技术生成

Leetcode 977. 有序数组的平方

题目链接:977. 有序数组的平方

思路:

想到了用双指针,即一个指针指向第一个负数,另一个指针指向第一个非负数。这种解法就是将元素从小到大开始填充,但是这种解法写起来太麻烦,因为需要判断两个指针分别走到尽头的情况,不然就会有数组越界的错误。后面想了下,其实用双向指针更好。

目前看来,双指针的题,对于我来说,易错点或者说把握不好的点在于两个指针分别指向的位置。写代码前,还是得多想想指针指向的位置。

P.S. 本题暴力解法时间复杂度为O(nlogn)

解题:成功

代码实现(√)

时间复杂度:O(n)

class Solution {
    public int[] sortedSquares(int[] nums) {
        int n = nums.length;
        int[] result = new int[n];
        int left = 0;
        int right = n - 1;
        int idx = n - 1;

        while(left <= right){
            if(Math.abs(nums[left]) <= Math.abs(nums[right])){
                result[idx] = nums[right] * nums[right];
                right--;
            }
            else{
                result[idx] = nums[left] * nums[left];
                left++;
            }
            idx--;
        }
        return result;
    }
}

另一个版本的双指针(这种太复杂了,但是逻辑上没问题)

// 可以跳过不看
class Solution {
    public int[] sortedSquares(int[] nums) {
        int n = nums.length;
        int positive = 0;
        int[] arr = new int[n];

        while(positive < n && nums[positive] < 0){
            positive++;
        }
        if(positive == 0){
            for(int i = 0; i < n; i++){
                nums[i] = nums[i] * nums[i];
            }
            return nums;
        }
        else{
            int negative = positive - 1;
            int idx = 0;
            while(negative >= 0 && positive < n){
                if(Math.abs(nums[negative]) <= nums[positive]){
                    arr[idx] = nums[negative] * nums[negative];
                    negative--;
                }
                else{
                    arr[idx] = nums[positive] * nums[positive];
                    positive++;
                }
                idx++;
            }
            while(negative < 0 && positive < n){
                arr[idx] = nums[positive] * nums[positive];
                positive++;
                idx++;
            }
            while(negative >= 0 && positive >= n){
                arr[idx] = nums[negative] * nums[negative];
                negative--;
                idx++;
            }
        }
        return arr;
    }
}

Leetcode 209.长度最小的子数组

题目链接:209.长度最小的子数组

思路:

看完题的第一想法是前缀和,但是想了下,这样不好解。而且印象中遇到过类似的题,不是用的前缀和。提示用滑动窗口,试了下,可行。滑动窗口,本质上还是双指针。

解题:成功

代码实现

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int n = nums.length;
        int left = 0;
        int len = Integer.MAX_VALUE;
        int sum = 0;

        for (int right = 0; right < n; right++){
            sum += nums[right];
            while(sum >= target){
                len = Math.min(len, right - left + 1);
                sum -= nums[left];
                left++;
            }
        }

        return len == Integer.MAX_VALUE ? 0 : len;
    }
}

时间复杂度:O(n)

主要是看每一个元素被操作的次数,每个元素在进入滑动窗口时操作一次,出去时操作一次,每个元素都是被操作两次,所以时间复杂度是 2 × n 也就是O(n)。

Leetcode 59. 螺旋矩阵 II

题目链接:59. 螺旋矩阵 II

思路:

看完题的第一想法是前缀和,但是想了下,这样不好解。而且印象中遇到过类似的题,不是用的前缀和。提示用滑动窗口,试了下,可行。滑动窗口,本质上还是双指针。

解题:成功(方法一)

代码实现

方法一

class Solution {
    public int[][] generateMatrix(int n) {
        int[] x = {0, 1, 0, -1};
        int[] y = {1, 0, -1, 0};
        int idx = 0;

        int[][] res = new int[n][n];
        int num = 1;
        int total = n * n;

        int i = 0;
        int j = 0;
        while(num <= total){
            res[i][j] = num;
            num++;
            int nextI = i + x[idx];
            int nextY = j + y[idx];
            if(nextI < 0 || nextI >= n || nextY < 0 || nextY >= n || res[nextI][nextY] != 0){
                idx = (idx + 1) % x.length; 
            }
            i += x[idx];
            j += y[idx];
        }
        return res;
    }
}

方法二:关键点在于保持区间定义

class Solution {
    public int[][] generateMatrix(int n) {
        int startx = 0;
        int starty = 0;
        int loop = 1;
        int offset = 1;
        int[][] res = new int[n][n];
        int count = 1;
        int i = 0;
        int j = 0;

        //坚持左闭右开区间定义
        while(loop <= n/2){
            //上方从左往右遍历
            for(j = starty; j < n - offset; j++){
                res[startx][j] = count++;
            }
            //右方从上往下遍历
            for(i = startx; i < n - offset; i++){
                res[i][j] = count++;
            }
            //下方从右往左遍历
            for(; j > starty; j--){
                res[i][j] = count++;
            }
            //左方从下往上遍历
            for(; i > starty; i--){
                res[i][j] = count++;
            }
            startx++;
            starty++;
            offset++;
            loop++;
        }
        if(n % 2 == 1){
            res[n/2][n/2] = count;
        }
        return res;
    }
}

数组篇总结

  1. 二分法(循环不变量原则,严格遵守区间定义)
  2. 双指针法
  3. 滑动窗口
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值