菜鸟前端刷算法第六天

35 阅读1分钟

题目描述 - 三数之和

给定一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != ji != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。返回所有和为 0 且不重复的三元组。

注意: 答案中不可以包含重复的三元组。

思路分析

最直白的方法是通过三重循环,遍历数组中所有元素, 找到三数之和为0的元素, 但是三重遍历时间复杂度是:O(n3)。我们可以双指针来降低复杂度。

先将数组进行升序排列,保证按顺序查找 abc 时,所找到的三个元素是不重复的。同时也方便下一步使用双指针减少一重遍历。

第一重循环遍历 a,对于每个 a 元素,从 a 元素的下一个位置开始,使用左右双指针 leftrightleft 指向 a 元素的下一个位置,right 指向末尾位置。进行下边的判断。

  1. 如果 nums[a] + nums[left] + nums[right] = 0,判断left右移,和 right 元素是否重复, 若不重复,则得到一个解,将其加入答案数组中,并继续将 left 右移,right 左移;
  2. 如果 nums[a] + nums[left] + nums[right] > 0,说明 nums[right] 值太大,将 right 向左移;
  3. 如果 nums[a] + nums[left] + nums[right] < 0,说明 nums[left] 值太小,将 left 右移。

代码:

/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var threeSum = function(nums) {
    nums = nums.sort((a,b)=>a-b)
    let ans = []
    for(let i=0; i<nums.length; i++){
        if(i>0 && nums[i]== nums[i-1]) continue
        let current = nums[i];
        let left = i+1, right = nums.length - 1;
        while(left < right){
            
            if(current + nums[left] + nums[right] == 0){
                while(left < right && nums[left] == nums[left + 1]){
                  left++
                }
                while(left < right && nums[right] == nums[right - 1]){
                   right--
                }
                ans.push([current, nums[left], nums[right]])
                right--
                left++
            }else if(current + nums[left] + nums[right] > 0){
                right--
            }else {
                left++
            }
        }
    }
    return ans
};