LeetCode Hot 100:15. 三数之和
题目
给你一个整数数组 nums
,判断是否存在三元组 [nums[i], nums[j], nums[k]]
满足 i != j
、i != k
且 j != k
,同时还满足 nums[i] + nums[j] + nums[k] == 0
。请你返回所有和为 0
且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例 1:
输入:nums = [-1,0,1,2,-1,-4] 输出:[[-1,-1,2],[-1,0,1]] 解释: nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。 nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。 nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。 不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。 注意,输出的顺序和三元组的顺序并不重要。
示例 2:
输入:nums = [0,1,1] 输出:[] 解释:唯一可能的三元组和不为 0 。
示例 3:
输入:nums = [0,0,0] 输出:[[0,0,0]] 解释:唯一可能的三元组和为 0 。
解析
为方便双指针以及跳过相同元素,先把 nums 排序。
枚举 nums[i],问题变成 nums[j]+nums[k]=−nums[i]。
题目要求答案中不能有重复的三元组。如何避免重复?
在外层循环中,如果发现 nums[i]=nums[i−1],那么 nums[i] 与后面两个数组成的和为 0 的三元组,nums[i−1] 也能组成一模一样的三元组,这就重复了,所以遇到 nums[i]=nums[i−1] 的情况,直接 continue。
在内层循环中,当三数之和等于 0 时,为避免把相同的三元组计入答案,跳过后续相同的 nums[j] 和 nums[k](也可以只跳过相同的 nums[j])。
优化
优化一:如果 nums[i] 与后面最小的两个数相加 nums[i]+nums[i+1]+nums[i+2]>0,那么后面不可能存在三数之和等于 0,break 外层循环。优化二:如果 nums[i] 与后面最大的两个数相加 nums[i]+nums[n−2]+nums[n−1]<0,那么内层循环不可能存在三数之和等于 0,但继续枚举,nums[i] 可以变大,所以后面还有机会找到三数之和等于 0,continue 外层循环。
------------------------------------------------
作者:灵茶山艾府
链接:https://leetcode.cn/problems/3sum/
来源:力扣(LeetCode)
答案
/*** @param {number[]} nums* @return {number[][]}*/
var threeSum = function(nums) {nums.sort((a,b) => a-b); //排序const ans = [];const len = nums.length;for(let k=0; k<len-2; k++) {//和前一个数相同,那么后面能组成0的两个数的答案相同,跳过该数if(k>0 && nums[k] === nums[k-1]) continue;//和后面两个最小的数之和都大于0,不可能找到等于0的两个数,跳出for循环if(nums[k] + nums[k+1] + nums[k+2] > 0) break;//和最后两个最大的数之和都小于0,内层循环固定位的数太小,回到外层循环找更大的数if(nums[k] + nums[len-2] + nums[len-1] < 0) continue;let i = k+1, j=len-1;while(i < j) {const s = nums[k] + nums[i] + nums[j];if(s < 0) { //换更大的加数i++;} else if(s > 0) { //换更小的加数j--;} else {ans.push([ nums[k], nums[i], nums[j]]); //等于0,加入答案for(i++; i<j && nums[i] === nums[i-1]; i++); //跳过重复的数for(j--; j<i && nums[j] === nums[j+1]; j--); //跳过重复的数}}}return ans;
};
复杂度分析
时间复杂度:O(n^2),其中 n 为 nums 的长度。排序 O(nlogn)。外层循环枚举第一个数,做法是 O(n) 双指针。所以总的时间复杂度为 O(n^2 )。
空间复杂度:O(1)。返回值不计入。忽略排序的栈开销。------------------------------------------------
作者:灵茶山艾府
链接:https://leetcode.cn/problems/3sum/
来源:力扣(LeetCode)