代码随想录算法训练营第2天 | 977.有序数组的平方、209.长度最小的子数组、59.螺旋矩阵II
977. 有序数组的平方
思路:
数组其实是有序的, 只不过负数平方之后可能成为最大数了。所以数组平方的最大值就在数组的两端,不是最左边就是最右边,不可能是中间。
需要注意的是while
里面的循环条件,每次i
或者j
都是变化1,,k
要从len-1
减到0
,填满res
数组,所以i=j
那次才是最后一次。
代码部分:
class Solution {
public int[] sortedSquares(int[] nums) {
int len = nums.length;
int[] res = new int[len];
int i = 0;
int j = len - 1;
int k = j;
while(i <= j){
if (nums[i] * nums[i] >= nums[j] * nums[j]){
res[k--] = nums[i] * nums[i];
i++;
}
else {
res[k--] = nums[j] * nums[j];
j--;
}
}
return res;
}
}
时间复杂度:
O(n)
空间复杂度:
O(n) //创建了一个长度为 n 的数组来存储结果
209. 长度最小的子数组
思路:
第一种想法,2层循环:第一层for循环控制区间的起始位置,第二层while循环控制区间的终止位置。
第二种:滑动窗口,就是不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果。
分析:如果第一层循环是循环的窗口的起点位置,终止位置需要一个一个往后移,去搜集所有 >= target
这些集合里面的所有的长度,再取一个最小的。这和两层循环的想法一样。所以第一层得是终点位置,然后动态的移动起点位置,从而减少时间复杂度。
终点位置随着for循环一个一个向后移动。如果我们的终点位置指向这里,这个集合里面的元素之和如果>= target
的话,说明这是符合条件的一个集合,我们收集它的长度之后,起点位置就可以向后移动了。
从而缩小当前这个集合,看下一个集合是否符合我们的条件。
就是当我们发现集合里面所有的元素和 >= target
,我们再去移动起始位置,这样就实现了动态调整起始位置,来去收集不同长度区间里面的和。
代码部分:
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int res = Integer.MAX_VALUE;
int subLen = 0;
int sum = 0, start = 0;
for(int end = 0; end < nums.length; end++){
sum += nums[end];
while(sum >= target){
subLen = end - start + 1;
res = res < subLen? res:subLen;
sum -= nums[start];
start++;
}
}
return res == Integer.MAX_VALUE? 0:res;
}
}
时间复杂度:
O(n)
看每一个元素被操作的次数,每个元素在滑动窗后进来操作一次,出去操作一次,每个元素都是被操作两次,所以时间复杂度是 2 × n 也就是O(n)
空间复杂度:
O(1)
59. 螺旋矩阵II
思路:
坚持循环不变量,左闭右开区间
模拟顺时针画矩阵的过程:
- 填充上行从左到右
- 填充右列从上到下
- 填充下行从右到左
- 填充左列从下到上
代码部分:
class Solution {
public int[][] generateMatrix(int n) {
int[][] res = new int[n][n];
int loop = 0;
int i, j; // i: col, j: row
int start = 0; // 每次循环的起点(start, start)
int count = 1;
while(loop < (n/2)){
loop++; //判断边界后,loop从1开始
// left to right - top
for(i = start; i < n - loop; i++){
res[start][i] = count++;
}
// top to bot - right
for(j = start; j < n - loop; j++){
res[j][i] = count++;
}
// right to left - bot
for(; i >= loop; i--){
res[j][i] = count++;
}
// bot to top - left
for(; j >= loop; j--){
res[j][i] = count++;
}
start++;
}
// 判断奇数时,需要给最中间赋值
if(n%2 == 1){
res[start][start] = count++;
}
return res;
}
}
时间复杂度:
O(n^2)
空间复杂度:
O(n^2)