1. 977有序数组的平方
1.1思路
看到题的时候还是想着用快慢指针,但是这个题引出了另一种两个指针的用法,也就是双指针,因为该非递减数组只看绝对值的话是从两头像中间变小的,所以就在两头放两个指针,然后比较大小,谁大push谁到res的数组里。
其实思维有点被局限在原地
了,因为前一天做的双指针的题都是快慢指针,而且大部分要求原地修改数组,本题并未要求只能操作原来数组
1.2 tips
-
for
循环条件是for(let i=0,j=nums.lenght-1;i<=j)
后面的++或者--可以不写,是放在了循环体内部了。 - 记得先化成绝对值,js里用:
Math.abs()
- 能用const记得用const
- array的
unshift()
性能不好,因为是往数组头添加元素,时间复杂度O(n),不如用push()
之后reverse()
,尽管reverse也是O(n)但是只用一次
1.3 另一思路:暴力破解
平方完了直接比大小排序就行了
- js中array有sort方法,但是该方法不同于C,他是把元素转为字符串按字符顺序排序,所以要对int排序,要结合js的arrow function,即:
array.sort((a,b) => a-b)
这样sort就多次调用这个比较方法,传入代比较的a和b,返回值大于0则a大,把b放前面 - sort()时间复杂度是O(nlogn)因为是
快速排序
.
2. 209长度最小的子数组
2.1思路:滑动窗口
正常暴力思路是两个for循环嵌套,第一个for负责起始位置,内层负责终止位置
- 说是滑动窗口,本质也是双指针,只是这次取的两个指针中间的集合
双指针不管是哪种变形,本质都是用一个for完成两个for的内容
对于暴力破解,外层控制起点,内层控制终点,那如果设计成双指针,一个负责start一个负责end,如果让for循环里的i还是代表start,那和暴力破解的思路其实就一样了。
这题的难点就在于,for的i代表的是end终点,让终点往前走,加和超过target之后在让start往前走,变成了一个窗口的整体向前滑动。
2.2 tips
- res要先设定个最大值,不然怎么动态更新
思路是let res =Infinity
;然后满足条件的话更新res = Math.min(res,end-start+1)
;然后sum要减去当前start位,从而继续让start往后判断
最后返回res === Infinity?0:res;
3. 59螺旋矩阵2
看到题的时候读题都读错了,以为是一行一行画的
3.1思路
没有涉及到算法,就是个模拟转圈的问题,难点在对于区间的划分要一直保持,就像前面做二分法的题一样,循环不变量,说白了就是对每条边的处理规则要统一,我的理解是每次循环的判断条件要一致。这里画圈如果保持左闭右开,就要让拐角处交给新边来画
容易犯的错误就是每条边处理方式不一样,说再具体点就是拐点,比如第一条边两个guardian都处理了,第二条边就从第二个数开始处理到最后一个拐点,第三条边又变成只处理第二个到倒数第二个了,所以每条边处理逻辑不一样的话,要考虑的情况会变的特别复杂。
3.2 tips
- 判断奇数:
n%2 == 1
- js里
/
是不会取整的,所以奇数/2得到的是浮点数,所以要除以二拿整数有两个方法:- 用
Math.floor()
该方法在坐标轴上向下取整(便于理解负数) - 用位运算,也会取整
n >> 1
- 用
- 循环次数是 n>>1次,找规律也能找出来
- js里新建二维数组的方法:
new Array(n).fill(0).map(()=>new Array(n).fill(0))
;- 这里用fill(0)是因为js里0是基础数据类型,而数组是引用数据类型,如果这里写成fill([]),那fill的每个数组因为是引用数据类型,所以如果你此时push一个arr[0].push['1'],整个一维数组的n个元素都会变成1
- 用.map处理后就没关系
3.2实现
真写起来之后发现全是问题。
用let center = res[mid][mid]
想在最后判断的时候改center值,才发现res返回的center部分动都没动..这种错误太低级了;
每次loop最后忘记修改offset值;
row对应startX,不是startY;
count初始值设成0;(设习惯了)
offset初始值设成0;(设习惯了)
对于下面的行和左边的列,判断条件都错写成了>0,而不是对应的startX/Y