977.有序数组的平方
文章讲解:programmercarl.com/0977.%E6%9C…
视频讲解: www.bilibili.com/video/BV1QB…
思路
本题除了逐一比较的暴力解法,更好的办法是使用双指针。本题数组有负数,所以平方后需要重排。越小的负数平方后越大。数组在原位平方后,从两边向中间靠拢,数值越来越小。那么我们可以想到,构建一个空数组用于存储最终排序结果,并使用双指针从两边开始遍历比较直到中间最小值,每次比较结果大的值就从新数组的尾部依次向前存储。
class Solution {
public int[] sortedSquares(int[] nums) {
int[] ans = new int[nums.length];
int left = 0, right = nums.length - 1;
int index = ans.length - 1;
while(left <= right)
{
if(nums[left] * nums[left] < nums[right] * nums[right]){
ans[index--] = nums[right] * nums[right];
right--;
}else
{
ans[index--] = nums[left] * nums[left];
left++;
}
}
return ans;
}
}
-
时间复杂度 O(n)
- 算法的核心是一个
while循环,它从数组的两端向中间遍历。无论数组的内容如何,每个元素都恰好被访问一次。因此,遍历的次数与数组nums的长度n直接相关。 在循环中的每一步,算法执行一些常数时间的操作。
- 算法的核心是一个
-
空间复杂度 O(n)
- 空间消耗主要由新创建的数组
ans决定,其大小与输入数组成线性关系,因此空间复杂度为 O(n),其中n是数组nums的长度。
- 空间消耗主要由新创建的数组
209.长度最小的子数组
文章讲解:programmercarl.com/0977.%E6%9C…
视频讲解: www.bilibili.com/video/BV1QB…
思路
这道题可以使用滑动窗口进行解决,其主要运动方式是,快指针进行数组遍历(扩展窗口),慢指针在后面进行窗口收缩。
对于本题,开始时,窗口大小为0。我们逐渐扩大窗口(增加窗口的右边界),直到窗口内的元素总和达到或超过 target。一旦实现这个条件,我们就尝试通过缩小窗口(即增加窗口的左边界)来找到更小的满足条件的子数组,同时继续维护元素总和。在整个数组中重复这个过程,我们能找到满足条件的最短子数组。如果找不到这样的子数组,我们返回 0。这个方法的效率在于它避免了重复检查每个可能的子数组,而是通过一次遍历来找到答案。
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int sum = 0;
int len = Integer.MAX_VALUE;
int i = 0, j = 0;
while(j < nums.length)
{
sum += nums[j++];
while (sum >= target) {
len = Math.min(len, j - i);
sum -= nums[i++];
}
}
return len == Integer.MAX_VALUE ? 0 : len;
}
}
时间复杂度是 O(n),空间复杂度是 O(1),因为只需要一次遍历数组,并且只使用了固定数量的额外空间。
59.螺旋矩阵II
文章讲解:programmercarl.com/0059.%E8%9E…
视频讲解:www.bilibili.com/video/BV1SL…
思路
这道题没有什么所谓的简单快捷方法,主要考察的是“模拟矩阵”,难点在于边界的确认。
public class Solution {
public int[][] generateMatrix(int n) {
int[][] matrix = new int[n][n];
int num = 1; // 初始化起始数字
int rowStart = 0;
int rowEnd = n - 1;
int colStart = 0;
int colEnd = n - 1;
while (rowStart <= rowEnd && colStart <= colEnd) {
// 遍历顶行
for (int j = colStart; j <= colEnd; j++) {
matrix[rowStart][j] = num++;
}
rowStart++;
// 遍历右列
for (int j = rowStart; j <= rowEnd; j++) {
matrix[j][colEnd] = num++;
}
colEnd--;
// 遍历底行
if (rowStart <= rowEnd) {
for (int j = colEnd; j >= colStart; j--) {
matrix[rowEnd][j] = num++;
}
}
rowEnd--;
// 遍历左列
if (colStart <= colEnd) {
for (int j = rowEnd; j >= rowStart; j--) {
matrix[j][colStart] = num++;
}
}
colStart++;
}
return matrix;
}
}
时间复杂度、空间复杂度都是 O(n^2),矩阵维度。
补充解释代码:
-
边界定义
- Row Start (
rowStart): 最上面一行的索引,初始为 0。 - Row End (
rowEnd): 最下面一行的索引,初始为n-1。 - Column Start (
colStart): 最左边一列的索引,初始为 0。 - Column End (
colEnd): 最右边一列的索引,初始为n-1。
- Row Start (
- 边界更新
在填充过程中,这些边界会根据以下规则更新:
- 填充上行 (
rowStart): 从colStart到colEnd。填充完成后,rowStart加1,因为上面的行已经填充完毕。 - 填充右列 (
colEnd): 从rowStart到rowEnd。填充完成后,colEnd减1,因为右边的列已经填充完毕。 - 填充下行 (
rowEnd): 如果rowStart <= rowEnd,则从colEnd到colStart。填充完成后,rowEnd减1,因为下面的行已经填充完毕。 - 填充左列 (
colStart): 如果colStart <= colEnd,则从rowEnd到rowStart。填充完成后,colStart加1,因为左边的列已经填充完毕。
- 边界检查
在每次填充后,需要检查边界条件以确定是否所有行和列都已经被正确处理。这是通过比较 rowStart 和 rowEnd,以及 colStart 和 colEnd 来实现的。如果 rowStart 超过了 rowEnd 或 colStart 超过了 colEnd,那么意味着所有的数字都已经被填充完毕,这时应该停止进一步的填充。
- 结束条件
循环继续进行,直到 rowStart 大于 rowEnd 或者 colStart 大于 colEnd,这意味着整个矩阵已被填满。
数组总结
后面再补充总结链接...