刷题神器
往期回顾
>【数组】|代码随想录算法训练营第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)
固定循环不变量
- 要找到固定的循环区间
- 要保存每次循环的起始位置

2218

被折叠的 条评论
为什么被折叠?



