题目描述如下:
大致思路: 将其转化为 nums[i] = nums[j] + nums[k];
写出第一个辅助函数, 接收一个数组和一个数字, 返回数组中任意两个元素的和等于该数字的集合
export function getArrByAdd(arr: number[], num: number) {
const map = new Map<number, number>();
const tmp: number[] = [];
for (let i = 0; i < arr.length; ++i) {
// 2. 如果map中有当前值, 即有与之前存储的值的和等于目标值, 并且判断之前有没有已经存储过该值
if (map.has(arr[i]) && !tmp.includes(arr[i])) {
tmp.push(arr[map.get(arr[i])!]);
tmp.push(arr[i]);
}
// 1. 存储数组中所有元素与目标值的差值
map.set(num - arr[i], i);
}
return tmp;
}
//测试代码如下:
test('getArrByAdd', () => {
expect(getArrByAdd([1, 2, 3, 4], 3)).toEqual([1, 2]);
expect(getArrByAdd([1, 2, 3, 4], 5)).toEqual([2, 3, 1, 4]);
expect(getArrByAdd([1, 2, 3, 4, 5, 5], 6)).toEqual([2, 4, 1, 5]);
expect(getArrByAdd([0, 1, 2, -1, -4], 1)).toEqual([0, 1, 2, -1]);
expect(getArrByAdd([-1, 1, 2, -1, -4], 0)).toEqual([-1, 1]);
});
第二个辅助函数, 获取相反数, 即 nums[j] + nums[k] + (-[nums]) = 0;
export function getOppositeNumber(num: number) {
return ~num + 1;
}
第三个辅助函数, 移出数组中某个指定元素, 防止最后的结果出现重复项
export function removeArr<T>(arr: T[], value: T) {
let index = arr.findIndex((p) => p === value);
return arr.filter((val, _index) => index !== _index);
}
最后主体函数
export function threeSum(nums: number[]): number[][] {
const res: number[][] = [];
//边界情况
if (nums.length < 3) return [];
let list = nums;
nums.forEach((item) => {
let tmp: number[] = [];
//
list = removeArr(list, item);
//获取与 item 的 和为 0 的数组元素, 需要剔除之前已经计算的项, 防止重复
tmp = (getArrByAdd(list, getOppositeNumber(item)));
if (tmp.length > 0) {
for (let i = 0; i < tmp.length; i += 2) {
//这里之前的函数设计的是返回一维数组, 所以需要这么处理, 其实应该也返回二维数组的
const val = [item, ...tmp.slice(i, i + 2)].sort((a, b) => a - b);
let flag = true;
if (res.length) {
//防止重复项
res.forEach((item) => {
if (item[0] === val[0] && item[1] === val[1] && item[2] === val[2]) {
flag = false;
}
});
}
flag && res.push(val);
}
}
});
return res;
}
//单元测试代码
test('threeSum', () => {
expect(threeSum([])).toEqual([]);
expect(threeSum([0])).toEqual([]);
expect(threeSum([0, 0, 0])).toEqual([[0, 0, 0]]);
expect(threeSum([1, 2, 4])).toEqual([]);
expect(threeSum([-1, 0, 1, 2, -1, -4])).toEqual([[-1, 0, 1], [-1, -1, 2]]);
});