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

977.有序数组的平方

LeetCode题目要求

给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
示例 1:
输入:nums = [-4,-1,0,3,10]
输出:[0,1,9,16,100]
解释:平方后,数组变为 [16,1,0,9,100]
排序后,数组变为 [0,1,9,16,100]

解题思路

由于给定的数组是有序且非递减(递增),而元素可能为负数,所以需要再平方后再排序

  • 思路1,先平方,再进行排序
class Solution {
    public int[] sortedSquares(int[] nums) {
        // 有序数组,非递减(递增),可能存在负数,平方后不一定是有序,因此需要再排序
        for (int i = 0; i < nums.length; i++) {
            int t = nums[i];
            nums[i] = t * t;
        }
        // 使用 Arrays.sort(int[]) 进行自然顺序排序
        Arrays.sort(nums);
        return nums;
    }
}
  • 思路2,双指针
class Solution {
    public int[] sortedSquares(int[] nums) {
        // 双指针怎么解决呢 
        // 输入:nums = [-4,-1,0,3,10]
        // 输出:[0,1,9,16,100]
        // 思路:遍历数组,做平方操作,平方后,如果值比后面的大,就与后面的交换
        int left = 0; // 左指针
        int right = nums.length - 1; // 右指针
        int[] result = new int[nums.length]; // 存储平方排序后的结果
        int k = right; // k 与 right 相等,从 k 位置开始放值
        while (left <= right) {
             //如果左指针平方 小于 右指针平方值,那么将大的值,放到 result k 的位置
            if (nums[left] * nums[left] < nums[right] * nums[right]) {
                result[k--] = nums[right] * nums[right];
                right--;
            } else {
                result[k--] = nums[left] * nums[left];
                left++;
            }
        }
        return result;
    }
}
重难点

双指针是个巧妙的解法,而且通过一个循环+指针移动就完成了。需要主要的点是:

  • while(left<=right) 这里使用的 <=, 需要和 right 的取值对应。
  • 指针移动,通过对比平方值,大的往右放,小的放左边

附:学习资料链接

209.长度最小的子数组

LeetCode题目要求

给定一个含有 n 个正整数的数组和一个正整数 target 。
找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。
 示例 1:
输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。

解题思路
  • 双指针,通过两个指针的移动,指针对应的值相加如果与 target 相等,记录两个指针间的长度。
    这个解法在 LeetCode 上跑居然超时了, 之前可以正常执行,很神奇
class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int i = 0;
        int j = 0;
        int len = nums.length;
        int result = Integer.MAX_VALUE;

        /* 分析过程
        0   1   2   3   4   5
        2,  3,  1,  2,  4,  3
        i   j                  2+3=5 < 7   下一次移动 j
        i       j              2+3+1=6 < 7 这里移动 j
        i           j          2+3+1+2=8>7 下一次移动 i
            i       j          3+1+2=6 < 7 这里移动 i
            i           j      3+1+2+4=10 > 7 下一次移动 i
                i       j      1+2+4=7  下一次移动i,与 target 相等,记录 j-i+1 = 4-2+1 = 3
                    i   j      2+4=6 < 7 这里移动 i,下一次移动 j
                    i       j  2+4+3=9 > 7  这里移动 j,下一次移动 i
                        i   j  4+3=7 这里移动 i,与 target 相等,  记录 j-i+1= 5-4+1 = 2, 比前值小,返回
        */

        while(i <= j && j < len) {
            int sum = calc(nums, i, j);
            if (sum >= target) {
                int l = j - i + 1;
                result = l < result ? l : result;
                i++;
            } else if (sum < target) {
                j++;
            }
        }
        return result == Integer.MAX_VALUE ? 0 : result;
    }

    private int calc(int[] nums, int i, int j) {
        int sum = 0;
        for(; i <= j; i++) {
            sum += nums[i];
        }
        return sum;
    }
}
  • carl 解法,滑动窗口
class Solution {

    public int minSubArrayLen(int target, int[] nums) {
        int left = 0;
        int sum = 0;
        int result = Integer.MAX_VALUE;
        // 遍历数组,过程中通过 left 与 right 指针形成一个滑动的窗口
        for (int right = 0; right < nums.length; right++) {
            // right 指针计算 每个滑动过的值的和
            sum += nums[right];
            // 如果滑动过的所有元素的和 大于等于 target ,那么就找到了
            while (sum >= target) {
                // 判断上一次的 result(窗口大小) 与当前窗口大小相比,取小的
                result = Math.min(result, right - left + 1);
                // 重新计算窗口内的和,但此时的操作是 将 left 指针右移,并且 sum 中把 left 指针的值减去,下一次再判断是否大于等于 target。
                sum -= nums[left++];
            }
        }
        return result == Integer.MAX_VALUE ? 0 : result;
    }
}
重难点

需要理解滑动窗口的思想:与双指针类似,通过两个指针形成一个窗口,然后通过移动左右指针,变换窗口的大小,形成与目标值匹配的大小

附:学习资料链接

59.螺旋矩阵II

LeetCode题目要求

给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。
示例:
输入:n = 3
输出:[[1,2,3],[8,9,4],[7,6,5]]

解题思路

根据题目,需要输出的是一个 int[n][n] 的二位数组,那么输出时需要模拟成一个顺时针的螺旋,输出方式为 从左到右 --> 从上到下 --> 从右到左 --> 从下到上,如此重复,直到输出为 n/2 圈;
代码实现

class Solution {
    public int[][] generateMatrix(int n) {
        int[][] result = new int[n][n];
        int startX = 0, startY = 0; // 每循环一圈的起始位置
        int loop = 0; //控制循环次数
        int mid = n / 2; // 矩阵中间位置
        int count = 1; // 填充数值
        int offset = 1; // 控制每个边遍历的长度,每次循环右边界收缩一位
        int i, j;
        
        while (loop++ < n / 2) { // 螺旋次数
            i = startX;
            j = startY;
            // 从左到右 左闭右开
            for (j = startY; j < n - offset; j++) {
                result[startX][j] = count++;
            }
            // 从上倒下 上闭下开
            for (i = startX; i < n - offset; i++) {
                result[i][j] = count++;
            }
            // 从右到左 右闭左开
            for (; j > startY; j--) {
                result[i][j] = count++;
            }
            // 从下到上 下闭上开
            for (; i > startX; i--) {
                result[i][j] = count++;
            }
            
            startX++;
            startY++;
            offset++;
        }

        if (n % 2 == 1) {
            result[mid][mid] = count;
        }

        return result;
    }
}
重难点
  • 确定好边界条件,需要注意的就是输出时,始终保持的是 闭开 原则,从开始到结束的形式为:左闭右开-> 上闭下开-> 右闭左开 -> 下闭上开
  • 如果 n 是奇数时,要对中间的点进行补充输出,才是完整的
    附:学习资料链接
posted @ 2022-12-30 21:01  blacksonny  阅读(17)  评论(0编辑  收藏  举报