209.长度最小的子数组
1.解题思路
首先理解是数组中找连续的元素的和是target
暴力解法:两个循环
两个for循环,然后不断的寻找符合条件的子序列,时间复杂度很明显是O(n^2),力扣会超时。
是以外循环为起点,内循环为终点的加
滑动窗口:双指针
所谓滑动窗口,就是不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果。
right指向终止位置,left指向起始位置,如果[left,right]中的和>=target,left右移找最小长度。
是以循环为终点,依次遍历。
时间复杂度:O(n)
2.遇到的问题
1.暴力解法时,result初始值设置错了,会在代码中给出
3.实现代码
暴力解法:
public int minSubArrayLen(int target, int[] nums) {
int result = nums.length+1; // 最终的结果
int sum = 0; // 子序列的数值之和
int subLength = 0; // 子序列的长度
for (int i = 0; i < nums.length; i++) { // 设置子序列起点为i
sum = 0;//每次进来sum置为0
for (int j = i; j < nums.length; j++) { // 设置子序列终止位置为j
sum += nums[j];
if (sum >= target) { // 一旦发现子序列和超过了target,更新result
subLength = j - i + 1; // 取子序列的长度
result = result < subLength ? result : subLength;
// 因为我们是找符合条件最短的子序列,所以一旦符合条件就break,进入下一个外循环
break;
}
}
}
// 如果result没有被赋值的话,就返回0,说明没有符合条件的子序列
// 这个地方错了,如果刚好要所有加起来等于最终结果,那就有问题
//return result == nums.length ? 0 : result;
return result == nums.length+1 ? 0 : result;//选个比最大范围大的,不包含在那个范围
}
滑动窗口:
public int minSubArrayLen(int target, int[] nums){
int result = nums.length+1;
int sum = 0; // 滑动窗口数值之和
int i = 0; // 滑动窗口起始位置
int subLength = 0; // 滑动窗口的长度
for (int j = 0; j < nums.length; j++) {
sum += nums[j];//left右移之后的sum加现在的right
// 注意这里使用while,每次更新 i(起始位置),并不断比较子序列是否符合条件
while (sum >= target) {
subLength = (j - i + 1); // 取子序列的长度
result = result < subLength ? result : subLength;
sum -= nums[i]; // 这里体现出滑动窗口的精髓之处,不断变更i(子序列的起始位置)
i++;//left右移
}
}
// 如果result没有被赋值的话,就返回0,说明没有符合条件的子序列
return result == nums.length+1 ? 0 : result;
}
4.题目总结
滑动窗口:确定何时扩大窗口,确定何时缩小窗口,在窗口滑动的哪个阶段更新结果,怎么移动窗口(不断变更i(子序列的起始位置))。
59.螺旋矩阵Ⅱ
1.解题思路
要写出正确的二分法一定要坚持循环不变量原则,即每一次循环的处理规则要一致
在这里我们是左闭右开原则,每一条边的边界条件都一样,每一次循环的条件也一样。
2.遇到的问题
1.边界条件错误
3.实现代码
public int[][] generateMatrix(int n) {
int[][] nums = new int[n][n];
int startX = 0, startY = 0; // 每一圈的起始点
int offset = 1;
int count = 1; // 矩阵中需要填写的数字
int loop = 1; // 记录当前的圈数
int i, j; // j 代表列, i 代表行;
while (loop <= n / 2) {
// 顶部
// 左闭右开,所以判断循环结束时, j 不能等于 n - offset
for (j = startY; j < n - offset; j++) {
nums[startX][j] = count++;
}
// 右列
// 左闭右开,所以判断循环结束时, i 不能等于 n - offset
for (i = startX; i < n - offset; i++) {
nums[i][j] = count++;
}
// 底部
// 左闭右开,所以判断循环结束时, j != startY
for (; j > startY; j--) {
nums[i][j] = count++;
}
// 左列
// 左闭右开,所以判断循环结束时, i != startX
for (; i > startX; i--) {
nums[i][j] = count++;
}
startX++;
startY++;
offset++;
loop++;
}
if (n % 2 == 1) { // n 为奇数时,单独处理矩阵中心的值
nums[startX][startY] = count;
}
return nums;
}
4.题目总结
可以发现这里的边界条件非常多,在一个循环中,如此多的边界条件,如果不按照固定规则来遍历,那就是一进循环深似海,从此offer是路人。