leetcode第15题:3 Sum(C++,hash表法,巧妙避免重复解)

题目描述

Given an array nums of n integers, are there elements a, b, c in nums such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.
Note:The solution set must not contain duplicate triplets.
Example:

Given array nums = [-1, 0, 1, 2, -1, -4],

A solution set is:
[
  [-1, 0, 1],
  [-1, -1, 2]
]

解题思路及代码示例

  • 观察解集,每一个解中的三个数有序,不同解之间有序,因此应先对数组进行排序
  • 如何避免重复解
  • 该问题是查找问题,可以考虑使用哈希表

暴力破解法

暴力破解法使用了三层循环,超时

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        vector<vector<int>> result;
        if (nums.size() >=3 )//数组长度小于三时,返回空向量
        {
            int flag = 0;
            for (auto it1=nums.begin(); it1!=nums.end()-2; ++it1)
            {
                //第二次及以后循环中,若相邻元素相同,则跳至相同元素中的最后一个元素
                if ((it1-nums.begin())>0 && *it1==*(it1-1)) continue;
                for (auto it2=it1+1; it2!=nums.end()-1; ++it2)
                {
                    //第二次及以后循环中,若相邻元素相同,则跳至相同元素中的最后一个元素
                    if ((it2-it1)>1 && *it2==*(it2-1)) continue;//
                    for (auto it3=it2+1; it3!=nums.end(); ++it3)
                    {
                        //找到一组解后,跳出最后一层循环
                        if (*it1 + *it2 + *it3 == 0)
                        {
                            result.push_back({*it1, *it2, *it3});
                            break;
                        }
                    }
                }
            }
        }
        return result;
    }
};

哈希表法

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        vector<vector<int>> result;
        unordered_map<int, int> hash;
        if (nums.size() >=3 )
        {
            int flag = 0;
            //构建hash_map
            for (auto it0=nums.begin(); it0!=nums.end(); ++it0)
                hash[*it0] = it0 - nums.begin();
            for (auto it1=nums.begin(); it1!=nums.end()-2; ++it1) //此循环确定解中的第一个数
            {
                //若相邻元素相同,则跳至相邻元素的最后一个
                if ((it1-nums.begin())>0 && *it1==*(it1-1)) continue;
                for (auto it2=it1+1; it2!=nums.end()-1; ++it2) //此循环确定解中的第二个数
                {
                    //解中的第三个数通过hash表查找
                    int tmp = -(*it1 + *it2);
                    //在hash表中找到对应数字,并且该数字对应的下标大于解中第二个数字对应的下标时进入条件语句
                    //第二个条件保证在第二个数所在位置之后查找第三个数以避免重复解
                    if (hash.find(tmp) != hash.end() && hash[tmp]>it2-nums.begin())
                    {
                        result.push_back({*it1, *it2, tmp});
                        while ((nums.end()-it2)>2 && *it2==*(it2+1)) ++it2;//若相邻元素相同,跳至相同元素的最后一个元素
                        continue;//能进入条件语句,说明已经找到一组解,则直接进行下一次循环,在新的第二个数下,找解
                    }
                    while ((nums.end()-it2)>2 && *it2==*(it2+1))
                        ++it2;
                }
            }
        }
        return result;
    }
};

Runtime: 316ms Memory: 15.5MB
可以看到,相较于暴力破解法,使用哈希表确实能有效减少运行时间

参考代码

该代码从该题目下的讨论区中得到,非常巧妙,上述提到的哈希表法借鉴了该解法中避免重复解的技巧

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
    sort(nums.begin(), nums.end());
    vector<vector<int>> res;
    for (unsigned int i=0; i<nums.size(); i++) {
        if ((i>0) && (nums[i]==nums[i-1]))
            continue;
        int l = i+1, r = nums.size()-1;
        while (l<r) {
            int s = nums[i]+nums[l]+nums[r];
            if (s>0) r--;
            else if (s<0) l++;
            else {
                res.push_back(vector<int> {nums[i], nums[l], nums[r]});
                while (l < r && nums[l]==nums[l+1]) l++;
                while (l < r && nums[r]==nums[r-1]) r--;
                l++; r--;
            }
        }
    }
    return res;
    }
};

Runtime: 116ms Memory: 15MB

猜你喜欢

转载自blog.csdn.net/weixin_42075898/article/details/90043692