- 今日学习的文章链接和视频链接
- 自己看到题目的第一想法
- 看完代码随想录之后的想法
- 自己实现过程中遇到哪些困难
- 今日收获,记录一下自己的学习时长
题目链接
209.长度最小的子数组
题目建议:本题关键在于理解滑动窗口,这个滑动窗口看文字讲解 还挺难理解的,建议大家先看视频讲解。 拓展题目可以先不做。
题目链接:https://leetcode.cn/problems/minimum-size-subarray-sum/
文章讲解:https://programmercarl.com/0209.长度最小的子数组.html
视频讲解:https://www.bilibili.com/video/BV1tZ4y1q7XE
59.螺旋矩阵II
题目建议:本题关键还是在转圈的逻辑,在二分搜索中提到的区间定义,在这里又用上了。
题目链接:https://leetcode.cn/problems/spiral-matrix-ii/
文章讲解:https://programmercarl.com/0059.螺旋矩阵II.html
视频讲解:https://www.bilibili.com/video/BV1SL4y1N7mV/
58.区间和
前缀和是一种思维巧妙很实用 而且很有容易理解的一种算法思想
文章讲解:https://www.programmercarl.com/kamacoder/0058.区间和.html
44.开发商购买土地
https://www.programmercarl.com/kamacoder/0044.开发商购买土地.html
总结
题目建议:希望大家也做一个自己对数组专题的总结
文章链接:https://programmercarl.com/数组总结篇.html
解题思路
209.长度最小的子数组
没啥头绪,看了好一会暴力解法才明白是怎么运行的。
- 外层用来循环整个数组
- 内层用来循环当前下标及其之后所有数的和
- 直到循环完后找到最小的length
- 相当于两个
滑动窗口的思想就不需要内层循环,用两个指针
-
指针i用来循环整个数组
-
指针j会在sum大于等于目标值时,从sum中减去当前值并向右移动
-
所以这个最坏的情况就是全是目标值-1的值组成的数组,指针j每走一步,i都需要走一步。即时间复杂度最坏为O(2n)
59.螺旋矩阵II
- 需要想好边界问题,一直保持左闭右开的规则,不停的更新二维数组的值
- 需要找出循环次数,也就是转几次圈
- 如何转内圈,需要定义偏移量,保证在转内圈的时候能正确赋值
- 特殊处理 n 为奇数的情况,也就是最中间的值的更新,找到最中间值的下标
题解
209.长度最小的子数组
/** * 暴力解法 * @param {number} target * @param {number[]} nums * @return {number} */var minSubArrayLen = function(target, nums) { // 定义一个足够大的长度 let result = 999999999999 let subLength = 0; // 子数组长度 for (let i = 0; i < nums.length; i++) { let sum = 0 // 每次从头开始计时 for (let j = i; j < nums.length; j++) { sum = sum + nums[j] // 计算和 if (sum >= target) { // 如果大于等于目标值 subLength = j - i + 1 // 得到数组长度 result = result < subLength ? result : subLength // 和之前的长度做比较,谁短就是谁 break // 找符合条件最短的子序列,所以一旦符合条件就break,没必要再加sum了 } } } // 如果result没有被赋值的话,就返回0,说明没有符合条件的子序列 return result === 999999999999 ? 0 : result};
/** * 滑动窗口解法 * @param {number} target * @param {number[]} nums * @return {number} */var minSubArrayLen = function(target, nums) { // 定义一个长度结果 let res = 999999999999 // 子数组的长度 let subLen = 0 // 定义一个窗口初始下标 let i = 0 // 和 let sum = 0 for (let j = 0; j < nums.length; j++) { // 相对于暴力解法,这里的sum在相加之后不用break sum = sum + nums[j] // 一旦大于等于目标值,就检查最小长度 // 这里一定要用 while,因为可能会出现[1,1,1,1,100],target 为 100 // 滑动窗口为[1,1,1,1,100]时,当 j 移动到 100 时,只会判断一次 // 如果i不继续往右移动,得出的 length = 5, 实际上是 2,[1,100] while (sum >= target) { // 得到子数组长度 subLen = j - i + 1 // 检查最小长度 res = res < subLen ? res : subLen // 减去初始位置的值,直到让sum小于目标值 sum = sum - nums[i] // 并且移动窗口起始位置, i++ } } return res === 999999999999 ? 0 : res};
59.螺旋矩阵II
const generateMatrix = function(n) { // 定义矩阵,用 0 填满 let res = new Array(n).fill(0).map(() => new Array(n).fill(0)) // 整体要循环的次数,n= 3,则转一圈就行,中间的特殊处理,n=4,则要转两圈 let loop = Math.floor(n/2) // 如果n 为奇数,则需要特殊处理最中间的值,它的坐标就是 n/2 let mid = Math.floor(n/2) // 定义起始值,[i,j],startX在二维数组为为 i 的起始值,但在坐标轴上为 Y轴,startY为 j 的值 let startX = 0 let startY = 0 // 偏移量,每转一圈,就需要加 1,就可能转内圈 let offset = 1 // 填充数字 let count = 1 // loop > 0 才转 while (loop--) { // i坐标 let row = startX // j 坐标 let col = startY // 左上到右上(左闭右开) // n-offset 就是为了左闭右开 // 假设 n = 5, 则 n-offset = 4,只需要循环1,2,3,4。5 则留给其他边处理 // 不停推动 col,也就是 j 向右移动 for (;col < n-offset; col ++) { res[row][col] = count ++ }
// 右上到右下(左闭右开) // 不停推动 row,也就是 i 向下移动 for (;row < n-offset;row ++) { res[row][col] = count ++ }
// 右下到左下(左闭右开) // 不停推动 col,也就是 j 向左移动 for (;col> startY; col --) { res[row][col] = count ++ } // 左下到左上 // // 不停推动 row,也就是 i 向上移动 for (;row > startX; row --) { res[row][col] = count ++ } // 进入第二圈的时候,起始坐标[i,j]都需要+1,才能进内圈 startX ++ startY ++ // 偏移量也需要+1,保证左闭右开 offset ++ } // 特殊处理奇数 n 的情况,手动更新最中间的值 if (n%2 === 1) { res[mid][mid] = count }
return res
};
收获
题解能看懂,也能写出来,但是感觉没有什么通用性的收获。对我来说虽然都是数组的题目,但是解题思路不具备通用性。差不多是那种从没头绪⇒看题解⇒原来可以这样理解⇒理解了⇒下一道题又困住了。回头再刷几道数组题看看,估计还是我刷题刷少了。