977.有序数组的平方
题目链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台
视频讲解: 双指针法经典题目 | LeetCode:977.有序数组的平方_哔哩哔哩_bilibili
刚开始没想到双指针该如何去用,第一时间想的是先平方再用Arrays.sort方法排序
class Solution {
public int[] sortedSquares(int[] nums) {
int left = 0, right = nums.length - 1;
int res[] = new int[nums.length];
int index = nums.length - 1;
while(left <= right) {
if (nums[left] * nums[left] < nums[right] * nums[right]) {
res[index] = nums[right] * nums[right];
right--;
index--;
} else {
res[index] = nums[left] * nums[left];
left++;
index--;
}
}
return res;
}
}
209.长度最小的子数组
题目链接:https://leetcode.cn/problems/minimum-size-subarray-sum/
视频讲解:https://www.bilibili.com/video/BV1tZ4y1q7XE
滑动窗口的思想,本质还是双指针(很重要的两个问题1.想清楚起始位置怎么移动 2.for循环里的参数表示的是终止位置)
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int left = 0;
int ans = Integer.MAX_VALUE;
int sum = 0;
for (int right = 0; right < nums.length; right++) {
sum += nums[right];
// while (s - nums[left] >= target)
// s -= nums[left++];
// if (s >= target)
// ans = Math.min(ans, right - left + 1);
while (sum >= target) {
ans = Math.min(ans, right - left + 1);
sum -= nums[left];
left++;
}
}
return ans == Integer.MAX_VALUE ? 0 : ans;
}
}
为什么可以简化
可以简化的原因是,内层的while
循环(while (s >= target) { ... }
)已经包含了原始方法中的所有必要步骤。每当子数组的和达到或超过target
时,我们都会尝试通过移动left
来减小子数组的长度,同时保证子数组的和仍然满足条件。这一过程自然地包括了原始方法中检查left
移动后的子数组和的步骤。
9.螺旋矩阵II
题目链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台
文章讲解:代码随想录
视频讲解:一入循环深似海 | LeetCode:59.螺旋矩阵II_哔哩哔哩_bilibili
class Solution {
public int[][] generateMatrix(int n) {
int res[][] = new int[n][n];
int loop = 0;
int start = 0;
int count = 1;
int i, j;
while (loop++ < n / 2) {
for (j = start; j < n - loop; j++) {
res[start][j] = count++;
}
for (i = start; i < n - loop; i++) {
res[i][j] = count++;
}
for (; j >= loop; j--) {
res[i][j] = count++;
}
for (; i >= loop; i--) {
res[i][j] = count++;
}
start++;
}
if (n % 2 == 1) {
res[n / 2][n / 2] = count;
}
return res;
}
}
class Solution {
public int[][] generateMatrix(int n) {
int[][] res = new int[n][n];
int loop = 0;
int start = 0;
int count = 1;
while (loop < n / 2) {
// Top row
for (int j = start; j < n - loop; j++) {
res[start][j] = count++;
}
// Right column
for (int i = start + 1; i < n - loop; i++) {
res[i][n - loop - 1] = count++;
}
// Bottom row
for (int j = n - loop - 2; j >= loop; j--) {
res[n - loop - 1][j] = count++;
}
// Left column
for (int i = n - loop - 2; i > start; i--) {
res[i][loop] = count++;
}
start++;
loop++;
}
// If n is odd, set the center value
if (n % 2 == 1) {
res[n / 2][n / 2] = count;
}
return res;
}
}
思考:loop++放到循环体内为什么就会下标越界
想象一下,你正在填充一个矩阵,就像你在画一个方框一样,你从左上角开始画,然后向右画,到达右上角,然后向下,接着向左,最后向上回到起点,但是每次你画完一个方框,你的下一个方框会比上一个小一圈。
在你的代码中,变量loop
表示你已经画了多少个这样的方框,而start
表示你开始画新方框的位置。
原始代码中,你在while
循环开始之前检查loop
的值,然后在循环的最后增加loop
。这意味着在整个循环体内,loop
的值保持不变。
但是当你把loop++
放在while
循环的条件中时,情况就变了。在每次循环开始之前,loop
都会增加。这样,你检查loop
值的时候,它已经比你期望的要大了。这意味着你的方框会从更内圈开始画,你的方框会比预期小,而且你会提前停止画方框,因为你认为自己已经画了足够多的方框。
在螺旋矩阵的代码中,loop
的值决定了你在矩阵中填充数字的边界。如果loop
在循环开始之前就递增,你实际上是在填充下一圈的边界,而不是当前的边界。所以,当你在while
循环条件中递增loop
时,你在每一圈实际上少填充了最外层的一圈数字。
这就是为什么仅仅改变loop
递增的位置会导致结果有很大差异。每次循环的正确边界对于生成正确的螺旋矩阵至关重要。希望这次解释更清晰了。
在循环条件内填充顺序如上图所示。