2023/7/27 任务
977.有序数组的平方 ,209.长度最小的子数组 ,59.螺旋矩阵II ,总结
977.有序数组的平方
本题关键在于理解双指针思想
(解法一)暴力解法
直接将元素平方后数组进行快排。
时间复杂度O(n + nlogn), 可以说是O(nlogn)的时间复杂度。
(解法二)双指针
数组平方后,最大值可能在最左或最右端。
int i = len - 1
原本写的时候没有想到数组元素从后往前遍历加,还写个一个反转数组…
class Solution {
public int[] sortedSquares(int[] nums) {
int len = nums.length;
int left = 0;
int right = len - 1;
int[] res = new int[len];
int i = len - 1;
while (left <= right) {
if (nums[left] * nums[left] > nums[right] * nums[right]){
res[i--] = nums[left] * nums[left];
left++;
} else {
res[i--] = nums[right] * nums[right];
right--;
}
}
return res;
}
}
时间复杂度O(n)
209.长度最小的子数组 ⭐
本题关键在于理解滑动窗口
(解法一)暴力解法
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int len = Integer.MAX_VALUE;
for (int i = 0; i < nums.length; i++) {
int sum = 0;
for (int j = i; j < nums.length; j++) {
sum += nums[j];
if (sum >= target) {
int tmp = j - i + 1;
len = Math.min(len, tmp);
break;
}
}
}
return len == Integer.MAX_VALUE ? 0 : len;
}
}
自己的问题版
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int sum = 0;
int len = Integer.MAX_VALUE;
int tmp = 0;
int i = 0;
boolean flag = false;
for (int j = 0; j < nums.length; j++) {
sum += nums[j];
tmp++;
if (sum >= target) {
len = len < tmp ? len : tmp;
tmp = 0;
sum = 0;
j = ++i;
flag = true;
}
}
if (!flag) return 0;
return len;
}
}
第一次写的时候想到了类似双指针,但是没理解到 j 应该代表终止位置;
记录长度用的是拿一个变量每次循环都++记录,但其实可以直接 j - i + 1;
比较最短用了三目,但可以直接min;
if 应该写成 while,只要sum还大于等于目标值,就继续移动滑动窗口;
sum不用清零重新算,结合while,滑动窗口;
最后返回值用三目判断可能更好。
(解法二)滑动窗口
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int sum = 0;
int len = Integer.MAX_VALUE;
int i = 0;
for (int j = 0; j < nums.length; j++) {
sum += nums[j];
while (sum >= target) {
len = Math.min(len, j - i + 1);
sum -= nums[i++];
}
}
return len == Integer.MAX_VALUE ? 0 : len;
}
}
滑动窗口的精妙之处在于根据当前子序列和大小的情况,不断调节子序列的起始位置。从而将O(n^2)暴力解法降为O(n)。
59.螺旋矩阵II ⭐
本题关键还是在转圈的逻辑,在二分搜索中提到的区间定义,在这里又用上了。
模拟顺时针画矩阵的过程:
填充上行从左到右
填充右列从上到下
填充下行从右到左
填充左列从下到上
坚持循环不变量原则,也就是画圈的规则,每画一条边都要坚持一致的左闭右开,或者左开右闭的原则。
class Solution {
public int[][] generateMatrix(int n) {
int[][] res = new int[n][n];
// 每圈循环开始的点
int start = 0;
int i = start, j;
// 填充的数字
int num = 1;
// 循环的次数
int loop = 0;
while (loop++ < n / 2) {
// 下面开始的四个for就是模拟左闭右开转了一圈
// 模拟上侧从左到右
for (j = start; j < n - loop; j++) {
res[i][j] = num++;
}
// 模拟右侧从上到下
for (i = start; i < n - loop; i++) {
res[i][j] = num++;
}
// 模拟下侧从右到左
for (; j > start; j--) {
res[i][j] = num++;
}
// 模拟左侧从下到上
for (; i > start; i--) {
res[i][j] = num++;
}
start++;
}
// 如果是奇数
if (n % 2 == 1) {
res[start][start] = num++;
}
return res;
}
}
时间复杂度 O(n^2): 模拟遍历二维矩阵的时间
空间复杂度 O(1)