摘要
这篇文章聚焦于三个算法题:LC-977. 有序数组的平方、LC-209. 长度最小的子数组和LC-59. 螺旋矩阵 II,并最后由ChatGPT对数组专题进行了全面总结。
1、LC-977.有序数组的平方
1.1 思路
双指针,分别指向数组的头尾,比较平方大小,从大到小依次放入新数组中,直到处理完所以元素
- 双指针往中间走
- 比较大小新数组留
1.2 代码
// 双指针,分别指向数组的头尾,比较平方大小,从大到小依次放入新数组中,直到处理完所以元素
public static int[] sortedSquares(int[] nums) {
int left = 0, right = nums.length-1;
int[] res = new int[nums.length];
int idx = nums.length -1;
while(left <= right) {
int num1 = nums[left] * nums[left];
int num2 = nums[right] * nums[right];
if(num1 > num2) {
res[idx] = num1;
left++;
} else {
res[idx] = num2;
right--;
}
idx--;
}
return res;
}
2、LC-209.长度最小的子数组
2.1 思路
双指针/滑动窗口 left, right分表代码连续子数组的头尾下标;sum表示该连续子数组的总和;res表示连续子数组的最小长度 right一直右移,直至sum大于等于target,计算出res;在满足条件的情况下,left也一直右移,不断更新res
- 左右指针滑窗舞,Sum为子数组求和妙
- 右指针向右移,Sum大于等于目标值,这是重要的起始
- 得到满足条件的长度,左指针缩小窗口,继续寻找最小的长度
2.2 代码
// 双指针/滑动窗口
// left, right分表代码连续子数组的头尾下标;sum表示该连续子数组的总和;res表示连续子数组的最小长度
// right一直右移,直至sum大于等于target,计算出res;在满足条件的情况下,left也一直右移,不断更新res
public static int minSubArrayLen(int target, int[] nums) {
int left = 0;
int sum = 0;
int res = Integer.MAX_VALUE;
for (int right = 0; right < nums.length; right++) {
sum += nums[right];
while (sum >= target) {
res = Math.min(res, right - left + 1);
sum -= nums[left];
left++;
}
}
return res != Integer.MAX_VALUE ? res : 0;
}
3、LC-59.螺旋矩阵II
3.1 思路
1、如何确定循环次数?
loop = n / 2;如果遇到 n 是奇数的情况,单独给中间的元素赋值
2、如果确定起始位置的结束位置
起始位置:startx = 0;starty = 0;每转一圈 startx ++,starty ++ 结束位置:endx = n-1, endy = n-1;每转一圈 endx --,endy --
3、如何表示二维数组中元素的值
定义计数变量 count,表示二维数组中元素的值
4、保持循环不变量(左闭右开)
- i=startx; j=[starty, endy)
- i=[startx, endx); j=endy
- i=endx; j=[endy, starty)
- i=[endx, startx); j=starty
3.2 代码
public static int[][] generateMatrix(int n) {
int[][] res = new int[n][n];
// 循环次数
int loop = n / 2;
// 起始位置
int startx = 0, starty = 0;
// 结束位置
int endx = n - 1, endy = n - 1;
// 二维数组元素值
int count = 1;
while (loop > 0) {
// i=startx;j=[starty, endy)
for (int j = starty; j < endy; j++) {
res[startx][j] = count;
count++;
}
// i=[startx, endx);j=endy
for (int i = startx; i < endx; i++) {
res[i][endy] = count;
count++;
}
// i=endx;j=[endy, starty)
for (int j = endy; j > starty; j--) {
res[endx][j] = count;
count++;
}
// i=[endx, startx);j=starty
for (int i = endx; i > startx; i--) {
res[i][starty] = count;
count++;
}
startx++;
starty++;
endx--;
endy--;
loop--;
}
// 处理n=奇数的情况
if (n % 2 == 1) {
res[startx][starty] = count;
}
return res;
}
4、总结
以下是对提到的五个数组算法题的总结:
-
LC-704. 二分查找:
- 主要思路:使用二分查找的方法在有序数组中查找目标元素。
- 具体步骤:使用两个指针,
left和right,初始化分别指向数组的起始和结束位置。然后,在每一轮循环中,计算中间位置mid,并比较nums[mid]与目标值target。如果相等,返回mid;如果小于target,则将left向右移动到mid + 1;如果大于target,则将right向左移动到mid - 1。 - 时间复杂度:O(log n),因为每一轮都将搜索范围减半。
-
LC-27. 移除元素:
- 主要思路:通过双指针遍历数组,将不等于目标值的元素移到前面。
- 具体步骤:使用两个指针,
newIdx和oldIdx,初始化分别为0。遍历数组,当发现元素等于目标值时,跳过;否则,将元素复制到newIdx位置,然后newIdx自增。最后,返回newIdx即为新数组的长度。 - 时间复杂度:O(n),其中 n 为数组长度。
-
LC-977. 有序数组的平方:
- 主要思路:利用有序数组的特性,通过双指针从两端向中间遍历,比较平方值的大小。
- 具体步骤:使用两个指针,
left和right,初始化分别指向数组的头和尾。比较nums[left]和nums[right]的平方值,将较大的平方值放入结果数组的末尾,然后移动对应的指针。重复此过程直到两个指针相遇。 - 时间复杂度:O(n),其中 n 为数组长度。
-
LC-209. 长度最小的子数组:
- 主要思路:使用双指针/滑动窗口技巧,维护一个子数组的窗口,不断调整窗口大小以满足条件。
- 具体步骤:使用两个指针,
left和right,分别初始化为0。left一直右移,直到子数组的和大于等于目标值target,此时记录子数组的长度。然后,继续移动left,不断尝试缩小子数组的长度,更新最小长度。重复这个过程直到right到达数组末尾。 - 时间复杂度:O(n),其中 n 为数组长度。
-
LC-59. 螺旋矩阵 II:
- 主要思路:按照顺时针的方向填充矩阵。
- 具体步骤:使用四个变量
top,bottom,left,right分别表示当前填充区域的上、下、左、右边界。然后,按照顺时针的顺序,从左到右、从上到下、从右到左、从下到上,填充矩阵的每一行或每一列。同时,更新边界变量,缩小填充区域。重复这个过程直到填充完成。 - 时间复杂度:O(n^2),其中 n 为矩阵的边长。
这些算法题涵盖了数组相关的不同应用场景,包括搜索、修改、转换和填充等操作,对于理解数组算法和双指针/滑动窗口技巧都非常有帮助。