[力扣 Hot100]三数之和

题目描述

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请你返回所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
出处

思路

把三数之和转化为两数之和,首先建立两数和的哈希表,然后遍历一遍找。
但是会超时,即使构建时控制key的范围为nums的子集,在set去重时仍会超时。
所以正确解法应该用双指针,这里两个方法都贴上。

代码

//超时308/312
class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        //构建哈希表
        unordered_map<int, vector<vector<int>>> hash;
        int max = *max_element(nums.begin(), nums.end());
        int min = *min_element(nums.begin(), nums.end());
        for(int j = 0; j < nums.size()-1; j++)
            for(int k = j+1; k < nums.size(); k++){
                if(-nums[j]-nums[k]>=min&&-nums[j]-nums[k]<=max)
                    hash[nums[j]+nums[k]].emplace_back(vector<int>{j, k});
            }
        set<vector<int>> ans; //保证不重复
        for(int i = 0; i < nums.size(); i++){
            if(hash.find(-nums[i]) != hash.end()){
                for(int j=0;j<hash[-nums[i]].size();j++){
                    vector<int> a = hash[-nums[i]][j];
                    if(i==a[0]||i==a[1]) 
                        continue;
                    a[0]=nums[a[0]];
                    a[1]=nums[a[1]];
                    a.push_back(nums[i]);
                    sort(a.begin(), a.end());
                    ans.insert(a);
            }
            }
        }
        vector<vector<int>> res;
        res.assign(ans.begin(), ans.end());
        return res;
    }
};

//正解
class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        vector<vector<int>> ans; 
        int n = nums.size();
        for(int i = 0; i < nums.size()-2; i++){
            if(nums[i] + nums[n-2] + nums[n-1] < 0||(i>0 && nums[i]==nums[i-1]))
                continue;
            if(nums[i]>0)
                break;
            
            int l = i + 1, r = nums.size() - 1;
            while (l < r) {
                if (nums[l] + nums[r] + nums[i] < 0) ++l;
                else if (nums[l] + nums[r] + nums[i] > 0) --r;
                else {
                    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;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值