力扣:15-三数之和

题目描述

给你一个包含 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,1,1]
输出:[]


示例 3:

输入:nums = [0,0,0]
输出:[[0,0,0]]
 

提示:

3 <= nums.length <= 3000
-105 <= nums[i] <= 105

来源:力扣(LeetCode)

思路

首先我用的暴力做法,三层for循环,不出意外的超时了。代码是这样的

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        int n=nums.size();
        vector<vector<int>>ans;
        sort(nums.begin(),nums.end());
        for(int i=0;i<n-2;i++)
        {
            if(i>0&&nums[i]==nums[i-1])
            continue;
            for(int j=i+1;j<n;j++)
            {
                if(j!=i+1&&nums[j]==nums[j-1])
                continue;
                for(int k=j+1;k<n;k++)
                {
                    if(k!=j+1&&nums[k]==nums[k-1])
                    continue;
                    if(nums[i]+nums[j]+nums[k]==0)
                    {
                        ans.push_back({nums[i],nums[j],nums[k]});
                    }
                }
            }
        }
        return ans;
    }
};

 需要注意的是连着两个数字不可以重复

然后就要想怎么优化了。第一层循环没有可以优化的地方,我们考虑另外两个数怎么得。我们这里利用双指针来消除无效解来提升效率

另外两个数我们分别用两个指针表示,从两边向内移动,如果三个数的和大于0的话,那么右边的指针要向左边移动,如果和小于0的话,左边的指针要向右边移动。因为数组是排好序的,既然我们要让和等于0,自然要移动指针来抵消多出来的值。

所以我们对上面的代码优化一下

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        int n=nums.size();
        vector<vector<int>>ans;
        sort(nums.begin(),nums.end());//排序
        for(int i=0;i<n-2;i++)
        {
            if(nums[i]>0)
            break;
            if(i>0&&nums[i]==nums[i-1])//排除相同数字
            continue;
            int l=i+1,r=n-1;
            while(l<r)
            {
                int s=nums[i]+nums[l]+nums[r];
                if(s<0)//如果和小于0
                {
                    //左指针右移
                    l++;
                    //排除相同数字
                    while(l<r&&nums[l]==nums[l-1]) l++;
                }
                else if(s>0)//如果和大于0
                {
                    //右指针左移
                    r--;
                    //排序相同数字
                    while(l<r&&nums[r]==nums[r+1]) r--;
                }
                else//和为0
                {
                    ans.push_back({nums[i],nums[l],nums[r]});
                    l++;
                    r--;
                    while(l<r&&nums[l]==nums[l-1]) l++;
                    while(l<r&&nums[r]==nums[r+1]) r--;
                }
            }
        }
        return ans;
    }
};

猜你喜欢

转载自blog.csdn.net/qq_52905520/article/details/126501858
今日推荐