二数之和可以用双指针的策略,但一定注意[1,1]找到和为2应该返回0,1但往往错返回成1,1。为了避免这种情况,可以借助find及findLast方法,一个是从前往后找,一个是从后往前找。
三数之和的难点在于双指针的配合达到和另外一个值相加为目标值的目的,其次,在找到这个值后,如何对左指针和右指针进行更新,这就需要整个数组是需要排序的,而排序函数的使用需要一定的基础arr.sort((a, b) => a - b),如果a-b那么升序,其次是sort函数直接改变原始值,所以不需要创建个新变量。排序之后的数组右指针向左移动,左指针+右指针的和变大,相反如果想减小这个值就需要左指针向右移动。另外是左右指针的初始值也需要考虑。
下面这部分代码是三数之和未经过优化的代码:
- 优化去重过程,当遍历到下一个元素后如果和上一个元素相同,那么跳过该层循环。注意,不需要和之前的元素比较,因为数组已经过排序,之前的元素一定比前一个小。
- 优化算法速度,当第一个元素>0时,那么无论怎么相加,都不可能找出三数之和=0的。
接下来是四数之和,考虑到去重较为麻烦,用对象key值存储较为方便。四数之和在三数之和的基础上对另外两个变量进行遍历,同样需要考虑这两个变量的界限问题,第一个值从0-(length-3),第二个值是从1-(length-2),另外两个值通过双指针进行获取,即三数之和的基础上。
基础知识
这道题虽然考察了算法,但是发现很多部分用到了基础知识,比如map、set、array、object等是如何遍历的?每个数据结构基本的操作是怎样的,应当是滚瓜烂熟的。其中用到的一个场景是去重操作,但是不知道object类型的key应当总是字符串类型的,还在写出object[[1,2,3]]=1后,遍历key值发现是字符串后一脸懵的状态,但是最后用split方法进行了数据类型的转换。同时也不清楚当数组类型作为key值时即使是相同的数组,地址不一样会被map认为不同的数组。下面总结了几种本题延伸出来的方法。
// 对象
const b1 = {
a: 1,
b: 2,
"1,2,3": 3,
};
b1[[2, 3, 4]] = 3;
// 对对象的key遍历
for (const a in b1) {
console.log(a);
console.log(b1[a]);
}
const array = [1, 2, 3];
for (const [key, value] of array.entries()) {
console.log(key, value);
}
for (const b of array) {
console.log(b);
}
// 获取对象的所有keys
Object.keys(b1);
// 获取对象的所有values
Object.values(b1);
// 同时对keys,value进行遍历
for (const [key, value] of Object.entries(b1)) {
console.log(key, value);
}
// set
const set = new Set([1, 2, 3, 4]);
set.has(1);
set.add(3).add(444);
set.delete(3);
for (const i of set) {
console.log(i);
}
// set.clear()
// map:
// map的key可以是任何类型,而object的key必须是字符串类型。
const map = new Map();
map.set("1", 2);
map.set(1, 2).set(2, 3).set(3, 4);
map.get(1);
map.has(1);
map.delete(1);
console.log(map.size);
// 注意array为对象类型,会定义在heap中,因此虽然值相同,但地址不同。
// 互相转换
// object 转array
// object 转 map
console.log(map.entries());
// 注意map array方法都用entries(),而object用object.entries(),很容易记住,只有object类型需要通过object.entries()才能用for of遍历,所以它特殊一些。
for (const [key, value] of map.entries()) {
console.log(key, value);
}
// set转array
const array1 = [...set];