15. 3Sum [三数之和]

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

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

例子
在这里插入图片描述
思路

可以参考二数之和的思路。

  • 二数之和 字典 (不合适,因为同一个数可能被多个组合需要,二数之和只需要一个答案,所以没有此顾虑)

对于每个人,拉上第二个人去找第三个人,此时就变成2数之和了,如果,第二个人被需要,直接输出,如果第二个人不被需要,则填入字典(第一个第二个人都不被需要):d[0-第一个人-第二个人]=[第一个人,第二个人]

  • 二数之和 双指针(需要先排序,好确定如何移动指针)推荐

先排序,遍历数组,对于每个数,取两个指针a,b,一个是它之后的数,一个是最后一个数,在a<b的情况下,如果和大于target,向前调b,如果和小于target,向后调a,如果,和为target,将此组合添加到结果
避免重复trick:

  1. 在外循环,如果现在的数和上一个数一样,就跳过,因为该数的选择比上一个数的选择更少,直接被囊括了
  2. 对于内循环,当找到一组答案后,如果nums[b]===nums[b-1],则跳过b-1,如果nums[a]==nums[a+1],则跳过a+1,因为nums[i]已经确定,该数跟上一个数一样的话,该组合也是重复的,故可略去

减少计算:

  1. 如果nums[i]+nums[i+1]+nums[i+2]>0 break #或nums[i]>0,则结束外循环。最小的数>0,则三数之和大于0,且后面的数都比nums[i]大,则后面的组合都有问题,
  2. 如果nums[i]+nums[n-1]+nums[n-2]<target continue #则最大的组合数都小于target直接下一个数
    答案
  • python
class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        nums.sort()#方便去重
        res = []
        n=len(nums)
        for i in range(n-2):
            if i>0 and nums[i]==nums[i-1]:
                continue
            if nums[i]+nums[i+1]+nums[i+2] > 0:#或者nums[i]>0
                break #最小的数>0,则三数之和大于0,且后面的数都比nums[i]大,则后面的组合都有问题,
            if nums[i]+nums[n-1]+nums[n-2]<0: continue
            a, b = i+1, n - 1
            
            while a <b:
                
                t = nums[a] + nums[i] + nums[b]
                if t < 0:
                    a += 1
                if t > 0:
                    b -= 1
                if t == 0:
                    res.append([nums[i], nums[a], nums[b]])
                    while a<b and nums[b]==nums[b-1]: 
                        b-=1
                    while a<b and nums[a]==nums[a+1]:
                        a+=1
                    a+=1
                    b-=1

        return res
  • c++
class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        vector<vector<int>> v;
        int n=nums.size();
        for (int i=0; i<n-2; i++)
        {
            int a=i+1,b=nums.size()-1;
            if (i>0 && nums[i]==nums[i-1]) continue;    
            if (nums[i]+nums[i+1]+nums[i+2]>0) break;//==nums[i]>0最小的数>0,则三数之和大于0,且后面的数都比nums[i]大,则后面的组合都有问题,        
            if (nums[i]+nums[n-1]+nums[n-2]<0) continue;
            while (a<b)
            {
                int t = nums[i]+nums[a]+nums[b];
                if (t<0) a++;
                if (t>0) b--;
                if (t==0)
                {
                    vector<int> temp = {nums[i],nums[a],nums[b]};
                    v.push_back(temp);
                    
                    while (a<b && nums[b]==nums[b-1]) b--;
                    while (a<b && nums[a]==nums[a+1]) a++;
                    a++;
                    b--;
                }
            }
        }
        return v;
    }
};
发布了78 篇原创文章 · 获赞 7 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/puspos/article/details/103145575