题目描述
本题选自 LeetCode 15. 三数之和
题目描述:
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例 1:
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
示例 2:
输入:nums = []
输出:[]
示例 3:
输入:nums = [0]
输出:[]
解题思路
暴力三重循环显然不是最优解。
这里,第一种思路是借鉴 LeetCode 1. 两数之和 的想法,基于 Map 或者 Set,三数之和相当于在两数之和的基础上增加一层循环。
第二种思路是,我们知道如果要 a + b === 0 那么有三种可能:
a = b = 0a < 0 & b > 0a > 0 & b < 0
因此,一个有序数组我们可以通过两边逼近的方式优化循环的查找过程。
题解
- 两数之和的 Map 解法
var twoSum = function (nums, target) {
let numMap = new Map([]);
for (let i = 0; i < nums.length; i++) {
let j = numMap.get(target - nums[i])
if (j !== undefined && j !== i) {
return [i, j];
} else {
numMap.set(nums[i], i);
}
}
};
- 三数之和的 Set 解法
var threeSum = function (nums) {
if (nums.length < 3) {
return [];
}
let arr = nums.sort();
let res = new Set();
for (let i = 0; i < arr.length; i++) {
if (i > 0 && arr[i - 1] === arr[i]) continue;
let set = new Set([]);
let a = arr[i];
for (let j = i + 1; j < arr.length; j++) {
let b = arr[j];
let c = -a - b;
if (set.has(c)) {
res.add([a, b, c].join(','));
} else {
set.add(b);
}
}
}
return [...res].map(val => val.split(','));
};
- 三数之和使用游动指标进行两边逼近的解法
/**
* @param {number[]} nums
* @return {number[][]}
*/
var threeSum = function (nums) {
if (nums.length < 3) {
return [];
}
let arr = nums.sort((a, b) => a - b);
let res = []
for (let i = 0; i < arr.length; i++) {
if (i > 0 && arr[i - 1] === arr[i]) continue;
let set = new Set([]);
let l = i + 1;
let r = nums.length - 1;
while (l < r) {
let sum = arr[i] + arr[l] + arr[r];
if (sum < 0) {
l++;
} else if (sum > 0) {
r--;
} else {
res.push([arr[i], arr[l], arr[r]]);
while (l < r && nums[l] === nums[l + 1]) l++;
while (l < r && nums[r] == nums[r - 1]) r--;
l++;
r--;
}
}
}
return res;
};
总结
在解题过程中,我们预先进行数组排序,可以跳过一些重复的选项