《leetcode15. 三数之和》

390 阅读1分钟

题目:

给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。

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

  示例:

给定数组 nums = [-1, 0, 1, 2, -1, -4],

满足要求的三元组集合为:
[
  [-1, 0, 1],
  [-1, -1, 2]
]

思路:要找三个数字,和为0.首先想到三重循环,分别循环i,j,k。判断三者之和是否为0。可是要求三元组不能重复,也就是说,[-1,-1,2] 和 [2,-1,-1] 是一个意思,不能重复。但是所给的原数组是乱序的,肯定会出现同样的元素不同的顺序。所以我们最好先把数组排序,升序排列,这样遍历的时候,[a,b,c] 就会以从小到大的顺序出现。排完序后,数组变成:[-4,-1,-1,0,1,2]

我们让i 从0~length-2 ; j从i+1 ~ length-1 ; k从j+1 ~ length

var threeSum = function(nums) {
    nums=nums.sort()
    let result=[],now
    for(let i=0;i<nums.length-2;i++){
        if(i===0 || nums[i]!==nums[i-1]){
            for(let j=i+1;j<nums.length-1;j++){
                if(j===i+1 || nums[j]!==nums[j-1]){
                    for(let k=j+1;k<nums.length;k++){                   
                        if((k===j+1 || nums[k]!==nums[k-1]) && nums[i]+nums[j]+nums[k]===0){
                            now=[nums[i],nums[j],nums[k]]
                            result.push(now)
                        }                  
                    }
                }              
            }
        }
    }
    return result
};

还有一种情况要考虑;如果排完序是这样的:[-4,-1,-1,-1,0,1,2],i=1,j=2,k=6时满足条件;然后j+1,j=3,j处的值还是-1,如果还考虑,那就会出现相同的结果[-1,-1,2] 。所以如果遇到i/j/k和上一次的值相等了,那就跳过,不考虑,直到和上一次的值不相等。但是如果此时j=i+1/k=j+1,如果j和i / k和j处的值相等,这个是要考虑在内的。所以每次进入三个循环的时候,要先判断,如果当前的i/j/k是第一个,那就可以往下进行;或者如果当前的i/j/k和上一次的不相等,也可以往下进行。这两个条件只要有一个成立,就可以。

但是三重循环,时间复杂度还是O(n3),显示超时了。

所以考虑其他方案:

双指针

我们先花费一些时间把数组变成有序的。参考两数之和,使用双指针的思路。每次固定一个i,i的范围从0~nums.length-2。然后分别让j=i+1,k=nums.length-1,让j和k从两端往中间移动。只要当j<k,就一直循环判断三数之和是否等于0.如果等于,那就直接Push,然后j右移,k左移;如果小于0,就说明当前的组合要再大一点,所以右移j;如果大于0,说明要再小一点,所以左移k。

var threeSum = function(nums) {
    nums=nums.sort((a,b)=>a-b)
    let result=[]
    for(let i=0;i<nums.length-2;i++){
        if(nums[i]>0){break}
        if(i===0 || nums[i]!==nums[i-1]){
            let j=i+1,k=nums.length-1
            while(j<k){
                let sum=nums[i]+nums[j]+nums[k]
                if(sum===0){
                    result.push([nums[i],nums[j],nums[k]])
                    j++
                    while(nums[j]===nums[j-1]){j++}
                    k--
                    while(nums[k]===nums[k+1]){k--}
                }else if(sum<0){
                    j++
                }else{
                    k--
                }
            }
        }
    }
    return result
};