数组
977 有序数组的平方
解题思路:
首先审题,题中描述是一个有序数组,数组中可能存在负数和正数,返回值是按照数的平方按非递减排序的数组。我们无法直接找到平方最小值在哪里,但是我们可以确定平方最大值一定是在数组的两端。于是就可以考虑用两个指针,一个指向数组最左端,一个指向最右端。每次对二者进行比较,然后进行赋值和下标更新。
题解(双指针):
时间复杂度:O(n)
空间复杂度:O(n)
class Solution {
public int[] sortedSquares(int[] nums) {
int n = nums.length;
int[] res = new int[n]; // 新数组
int left = 0; // 左指针
int right = n - 1; // 右指针
int index = n - 1; // 新数组下标
while (left <= right) {
if (Math.abs(nums[left]) > Math.abs(nums[right])) {
res[index] = nums[left] * nums[left];
left++;
} else {
res[index] = nums[right] * nums[right];
right--;
}
index--;
}
return res;
}
}
209 长度最小的子数组
题解1:
暴力解法: 直接遍历每个数,统计从每个数作为头节点开始向后累加,当长度大于等于 target 时记录子数组长度。
时间复杂度:O(n^2)
空间复杂度:O(1)
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int minLen = Integer.MAX_VALUE;
for (int i = 0; i < nums.length; i++) {
int sum = nums[i];
int len = 1;
if (sum >= target) return 1;
for (int j = i + 1; j < nums.length; j++) {
sum += nums[j];
len++;
if (sum >= target) {
minLen = Math.min(minLen, len);
break;
}
}
}
return minLen == Integer.MAX_VALUE ? 0 : minLen;
}
}
题解2:
滑动窗口: 当碰到子数组题时,可以考虑用滑动窗口。所谓滑动窗口,就是不断的调节子数组的起始位置和终止位置,从而得出我们要想的结果。
常用模版:for 循环
遍历数组 终止位置,内嵌一个while循环
,循环条件为 想要的结果。当已经达到了想要的结果时,再不断 收缩起始位置。
时间复杂度:O(n)
空间复杂度:O(1)
这里时间复杂度为 O(n) 的原因是,我们不能仅通过循环嵌套循环就断定为 O(n^2)。应该看数组中每个数实际被操作的次数。在此题中,数组中每个元素都被操作过两次,一次作为终止位置累加,一次作为起始位置累减。因此时间复杂度应是 O(2n) => O(n)。
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int minLen = Integer.MAX_VALUE; // 求最小值,所以初始化最大值
int start = 0; // 标记子数组的头下标
int sum = 0; // 统计子数组的和
int len = 0; // 记录子数组长度
// for循环遍历子数组的尾下标
for (int end = 0; end < nums.length; end++) {
sum += nums[end]; // 累加和
// 当长度大于等于target时,先收集结果,然后收缩头节点
while (sum >= target) {
len = end - start + 1;
minLen = Math.min(minLen, len);
sum -= nums[start];
start++;
}
}
return minLen == Integer.MAX_VALUE ? 0 : minLen;
}
}
59 螺旋矩阵II
解题思路:
比较经典的模拟题,先确定好四个边界,然后每次 for 循环后记得要收缩边界。
题解:
时间复杂度:O(n^2)
空间复杂度:O(n^2)
因为要填充 n*n 的数组,所以时间复杂度为 O(n^2);
除了返回的矩阵以外,空间复杂度为 O(1)。
class Solution {
public int[][] generateMatrix(int n) {
int[][] res = new int[n][n];
int left = 0; // 标记当前左边界
int right = n - 1; // 标记当前右边界
int top = 0; // 标记当前上边界
int bottom = n - 1; // 标记当前下边界
int num = 1; // 计数
while (num <= n * n) {
for (int i = left; i <= right; i++) {
res[top][i] = num;
num++;
}
top++;
for (int j = top; j <= bottom; j++) {
res[j][right] = num;
num++;
}
right--;
for (int i = right; i >= left; i--) {
res[bottom][i] = num;
num++;
}
bottom--;
for (int j = bottom; j >= top; j--) {
res[j][left] = num;
num++;
}
left++;
}
return res;
}
}
今日心得
今天的题做的比较轻松,可能一刷的印象比较深。滑动窗口还需要再多做几道巩固一下🌹。