【数组】|代码随想录算法训练营第2天| 977.有序数组的平方 、209.长度最小的子数组 、59.螺旋矩阵II 、【总结】

刷题神器

代码随想录

往期回顾

>【数组】|代码随想录算法训练营第1天| 704. 二分查找、27. 移除元素

题目

977. 有序数组的平方

题目:题目链接
文章:文章讲解
视频:视频讲解

  • 第一想法
    暴力求解,全部求平方然后再重新排序,时间复杂度是O(n+nlog n)
  • 学后思路
    有序数组的平方根,前提是数组是一个非递减顺序的要求,所以最大值在两边,最小是在中间,所以使用双指针由两边往中间遍历,产生的结果就是从最大到最小。时间复杂度为O(n)。

解法一: 暴力求解

求平方,然后快排序,代码忽略
时间复杂度是O(n+nlog n)=循环一次+排序一次

解法二: 双指针法

class Solution {
    public int[] sortedSquares(int[] nums) {
        // 结果集
        int[] result = new int[nums.length];
        // 结果集索引,因为结果要求从小到大,双指针结果从小到大,所以新数组循环从后往前
        int k = nums.length - 1;
        for (int i = 0, j = nums.length - 1; i <= j; ) {
            if (nums[i] * nums[i] > nums[j] * nums[j]) {
                result[k] = nums[i] * nums[i];
                i++;
            } else {
                result[k] = nums[j] * nums[j];
                j--;
            }
            k--;
        }
        return result;
    }
}
  • 题目总结
    • 注意左右指针递增和递减,注意循环跳出的判断条件
    • 因为结果要求是从小到大,双指针从大到小遍历,结果从大到小填充,注意数组边界

209. 长度最小的子数组

题目:题目链接
文章:文章讲解
视频:视频讲解

  • 第一想法
    两层循环,第一层循环控制数组的开头,第二层循环控制数组的结尾,然后遍历所有的开头和结尾的数组,每个数组的和,然后判断所有数组最短长度,时间复杂度O(n^2)。
  • 学后思路
    • 暴力解法,要注意判断最小值的逻辑和结尾的循环是从开始开始的也就是j=i
    • 滑动窗口,固定头指针,遍历为指针,然后当数组满足条件后,固定尾指针,遍历头指针,这种弹性的区间就是滑动窗口。时间复杂度O(n)。

解法一: 暴力解法

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int result = Integer.MAX_VALUE;
        for (int i = 0; i < nums.length; i++) {
            int sum = 0;
            // 注意结尾是从i开始的
            for (int j = i; j < nums.length; j++) {
                sum = sum + nums[j];
                if (sum >= target) {
                    int subLen = j - i + 1;
                    result = result < subLen ? result : subLen;
                    break;
                }
            }
        }
        result = result == Integer.MAX_VALUE ? 0 : result;
        return result;
    }
}

解法二: 滑动窗口

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int result = Integer.MAX_VALUE;
        int start = 0;
        int sum = 0;
        for (int end = 0; end < nums.length; end++) {
            sum = sum + nums[end];
            // 经典之处 1,1,1,1,100  target=100,左区间要循环判断
            while (sum >= target) {
                int subLen = end - start + 1;
                result = Math.min(result, subLen);
                sum = sum - nums[start];
                start++;
            }
        }
        return  result == Integer.MAX_VALUE ? 0: result;
    }
}
  • 题目总结
    • 暴力解法注意为指针的开始
    • 滑动窗口要注意找到区间后的收缩区间使用while

59. 螺旋矩阵 II

题目:题目链接
文章:文章讲解
视频:视频讲解

  • 第一想法
    看到螺旋矩阵,第一想法是顺时针顺序遍历,但是上下和左右数组长度不一样,遍历的过程中要控制区间。
  • 学后思路
    循环不变量区间,固定循环区间,使得所有的遍历区间都保持一致

解法一: 暴力解法

不推荐,要考虑边界问题特别麻烦,不建议大家尝试

解法二: 循环不变量

class Solution {
    public int[][] generateMatrix(int n) {
        int[][] result = new int[n][n];
        // 循环次数
        int loop = n / 2;
        // x=行 y=列 记录每一圈的循环开始节点
        int startx = 0, starty = 0;
        // 步长,决定的每次的固定循环长度
        int step = 1;
        int count = 1;
        int i, j;
        while (loop > 0) {
            // 从左向右 ,停在最后一位,但是不包含最后一位 j = n- step
            for (j = starty; j < n - step; j++) {
                result[startx][j] = count;
                count++;
            }
            // 从上向下 ,停在最后一位,但是不包含最后一位 i = n- step
            for (i = startx; i < n - step; i++) {
                result[i][j] = count;
                count++;
            }
            // 从右向左 ,停在最后一位,但是不包含最后一位
            for (; j > starty; j--) {
                result[i][j] = count;
                count++;
            }
            // 从下向上 ,停在最后一位,但是不包含最后一位
            for (; i > startx; i--) {
                result[i][j] = count;
                count++;
            }
            loop--;
            startx++;
            starty++;
            // 注意步长+1
            step++;
        }
				// 处理基数
        if (n % 2 == 1) {
            int center = n / 2;
            result[center][center] = n * n;
        }

        return result;
    }
}
  • 题目总结
    • 固定每次开始的起始位置
    • 注意每次都是顺时针便利,然后处理自增或者自减变量
    • 注意处理特殊情况就是基数情况,直接处理中心值

数组总结

文章:文章讲解

数组理论基础

  • 数组是连续的
  • 数组的值不能删除,只能覆盖

二分法

  • 要强调数组是顺序递增的
  • 注意区间的左闭右闭[left, right]还是左闭右开[left, right),循环条件的判断和区间的赋值
  • 注意计算middle的溢出问题,middle = left + (right-left)/2
  • 时间复杂度O(log n)

双子针法(快慢指针)

  • 注意快慢指针,快指针指向最新的数据,慢指针指向要覆盖的数据
  • 时间复杂度O(n)

双子针法 (前后指针)

  • 前后指针要注意结束的判断条件
  • 循环条件要在符合条件下的函数体内处理
  • 时间复杂度O(n)

滑动窗口

  • 滑动窗口也是双指针,但是遍历的是尾指针,通过来回固定头为指针的方式,控制弹性伸缩的区间,先找到大区间,在压缩区间到不符合条件为止,然后在扩大区间
  • 时间复杂度O(n)

固定循环不变量

  • 要找到固定的循环区间
  • 要保存每次循环的起始位置

你可能感兴趣的:(数据结构与算法,算法,矩阵)