题目
给你一个包含 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 = [] 输出:[]
提示
0 <= nums.length <= 3000
-105 <= nums[i] <= 105
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/3sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路:
咋一看,首先想到来个暴力穷举,三个数的话我们需要三层循环 ==> O(n * n *n )。 这个就不用试了,
肯定过不了的。看看怎么能把这个优化吧, 优化方向 O( n * n * n) ==> O (nn) ==> O(nlogn)。 在前面盛水最多的容器那题,我们使用了双指针技巧 成功把 O(n*n) 降到了 O(n) . 是不是很爽? 那当然,这里我们也可以继续用,毕竟是存储结构是数组。划重点存储结构为数组的,我们可以尝试用双指针法. 同时,排序后的数组使用二分查找的速度更快!!
/**
* @param {number[]} nums
* @return {number[][]}
*/
var threeSum = function(nums) {
let result = [];
// 对数组排序
nums = nums.sort((a,b)=>a-b);
// 这里遍历很有技巧,假设第一个数最大,第二个数第二大,第三个数最小
for (let i = 0; i < nums.length;i++){
if (nums[i] > 0) break;
// 排除值相同的元素
if (i > 0 && nums[i] === nums[i-1]) continue;
// 熟悉的双指针
let left = i+1;
let right = nums.length - 1;
// 双指针开始工作
while (left < right){
const sum = nums[i] + nums[left] + nums[right];
// 根据临时的sum来移动
if (sum > 0) {
right --;
} else if(sum < 0 ) {
left ++;
} else {
// 找到结果后的操作,第一入栈,第二排除相同元素,为下一次做准备
result.push([nums[i],nums[left],nums[right]]);
while (left < right && nums[left ] === nums[left+1]){
left ++;
}
while (left < right && nums[right] === nums[right - 1]){
right --;
}
left ++;
right --;
}
}
}
return result;
};
总结
数组题目无非以下几种方法:
- 穷举
- 双指针
- 二分(排序后的数组)
- 哈希