977.有序数组的平方
文章讲解:https://programmercarl.com/0977.%E6%9C%89%E5%BA%8F%E6%95%B0%E7%BB%84%E7%9A%84%E5%B9%B3%E6%96%B9.html
视频讲解: https://www.bilibili.com/video/BV1QB4y1D7ep
209.长度最小的子数组
文章讲解:https://programmercarl.com/0209.%E9%95%BF%E5%BA%A6%E6%9C%80%E5%B0%8F%E7%9A%84%E5%AD%90%E6%95%B0%E7%BB%84.html
视频讲解:https://www.bilibili.com/video/BV1tZ4y1q7XE
59.螺旋矩阵II
文章讲解:https://programmercarl.com/0059.%E8%9E%BA%E6%97%8B%E7%9F%A9%E9%98%B5II.html
视频讲解:https://www.bilibili.com/video/BV1SL4y1N7mV/
977.有序数组的平方
感悟有两点;
- 有序数组,最值只会出现在两端
- 双指针大法我觉得不要去记什么情况下去用,而是记住这个方法,拿到题目去试
209.长度最小的子数组
滑动窗口思路:
- 使用两个指针 𝑙𝑒𝑓𝑡 和 𝑟𝑖𝑔ℎ𝑡 来表示当前窗口的左右边界,初始时都指向数组的起始位置。right的作用是拓展,满足>=target的要求;left的作用是精简,满足最小长度的要求
- 移动右指针扩大窗口,直到窗口内的和大于等于 target。
- 当窗口内的和大于等于 target 时,记录当前窗口长度并尝试移动左指针缩小窗口,直到窗口内的和小于 target。
- 在移动左指针的过程中,更新最小长度。
- 重复上述过程,直到右指针遍历完整个数组。
感悟如下:
- 遵循卡哥教导,明确变量的含义,且不能改变,所以我打算每个变量定义的时候都加一行注释
- 惊喜发现这个和昨天题目一样,也是同向双指针,因此可以用昨天的方法,跑得快的right遍历数组作为主流程。
public class Array_209_MinimumSizeSubarraySum {
public int minSubArrayLen(int target, int[] nums) {
// minLength: 记录了当前满足要求的子串的最短长度
// total:表示当前子串的
// left表示找到的最短子串的左边界,right表示找到的最短子串的右边界
// 子串的范围是[left, right]
int minLength = Integer.MAX_VALUE;
int total = 0;
int left = 0;
int right = 0;
for (right = 0; right < nums.length; right++) {
total += nums[right];
if (total < target) {
continue;
} else {
while (total >= target) {
total -= nums[left];
left++;
}
left--;
total += nums[left];
int tempLength = right - left + 1;
minLength = Math.min(minLength, tempLength);
}
}
if (minLength == Integer.MAX_VALUE) return 0;
return minLength;
}
}
59. 螺旋矩阵 II
卡哥说的没错,这道题确实不考算法,考的是细心还有一点数列求和的数学知识
我拿到这道题,觉得整体去考虑很复杂,就想着能不能把它分解成某些基本操作。然后我发现对于n为偶数的矩形,可以把一个矩形分成很多层,螺旋填充矩阵的过程可以变成一层一层填充矩阵的过程;对于n为奇数的矩形,就是多了填一个中心的操作。
确定好这个基本操作后,我就思考完成这个操作需要哪些数据。思考一下我觉得需要这些数据:
- 这一层的起始坐标
- 这一层第一个要填充的值
- 这一层的宽度
然后就是一个找规律的过程,具体过程我放在下面
具体代码如下:
limit代表这个东西
public class Array_59_SpiralMatrixII {
public int[][] generateMatrix(int n) {
int[][] ans = new int[n][n];
if (n % 2 == 1) {
ans[(n - 1) / 2][(n - 1) / 2] = n * n;
}
// first代表要填充的那一层的左上角的坐标
// last代表要填充的那一层的右下角的坐标
// (因为每一层的左上和右下的横纵坐标都相等,所以传进去一个就行)
int first = 0;
int last = n - 1;
while (first < last) {
fillLayer(first, last, n, ans);
first++;
last--;
}
return ans;
}
// 这个函数的作用是填充一层。注意,在设计的时候没有把单一的一个元素看做一层
public static void fillLayer(int first, int last, int n, int[][] ans) {
// System.out.println("此时填充" + String.format("[%d,%d] -- [%d,%d]",first,first,last,last));
// limit的含义还是看图吧
int limit = last - first;
// num 是要填充的第一个值
int num = 4 * first * n - 4 * first * first + 1;
// x代表准备填充数据的二维坐标中的第一维,y是第二维
int x = first;
int y = first;
// 开始顺时针填充
// 填充第一条,即上侧
for (int i = 0; i < limit; i++) {
ans[x][y] = num;
y++;
num++;
}
// 填充第二条,即右侧
for (int i = 0; i < limit; i++) {
ans[x][y] = num;
x++;
num++;
}
// 填充第三条,即下侧
for (int i = 0; i < limit; i++) {
ans[x][y] = num;
y--;
num++;
}
// 填充第四条,即左侧
for (int i = 0; i < limit; i++) {
ans[x][y] = num;
x--;
num++;
}
}
public static void main(String[] args) {
Array_59_SpiralMatrixII array_59_spiralMatrixII = new Array_59_SpiralMatrixII();
array_59_spiralMatrixII.generateMatrix(3);
}
}