【力扣-哈希表】7、三数之和(15)

179 阅读1分钟

「这是我参与11月更文挑战的第5天,活动详情查看:2021最后一次更文挑战

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 = []
输出: []

示例 3:

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

思路

a+b+c = 0 , 使用两层for循环可以记录 a和b ,再用哈希法 确定 c = 0 - (a+b)的值是否在数组中出现过。也可以使用双指针法来解决。

哈希法

class Solution
{
    vector<vector<int>> threeSum(vector<int> &nums)
    {
        vector<vector<int>> ret;
        sort(nums.begin(), nums.end());
        

        // 找出三个数 a,b,c使得 a+b+c = 0
        // 令 a = nums[i] , b = nums[j] , c = -(a+b)
        for (int i = 0; i < nums.size(); i++)
        {
        
            // 排序后,如果第一个元素值大于0就无法构成三元组
            if (nums[i] > 0)
            {
                continue;
            }
            // 三元组中元素a去重
            if (i > 0 && nums[i] == nums[i - 1])
            {
                continue;
            }

            unordered_set<int> set;
            for (int j = i + 1; j < nums.size(); j++)
            {
                // 三元组中元素b去重
                if (j > i + 2 && nums[j] == nums[j - 1] && nums[j - 1] == nums[j - 2])
                {
                    continue;
                }
                int c = 0 - (nums[i] + nums[j]);
                if (set.find(c) != set.end())
                {
                    ret.push_back({nums[i], nums[j], c});
                    // 三元组中元素c去重
                    set.erase(c);
                }
                else
                {
                    set.insert(nums[j]);
                }
            }
        }
        return ret;
    }
};

双指针

class Solution
{
    
    // 双指针法
    vector<vector<int>> threeSum(vector<int> &nums)
    {
        vector<vector<int>> ret;
        sort(nums.begin(), nums.end());

        for (int i = 0; i < nums.size(); i++)
        {
            // 排序后,若第一个元素值大于0,则无法构成三元组
            // 返回结果数组
            if (nums[i] > 0)
            {
                return ret;
            }

            // 第一个数与相邻的元素相同时去重
            if (i > 0 && nums[i] == nums[i - 1])
            {

                continue;
            }
            int left = i + 1;
            int right = nums.size() - 1;

            while (left < right)
            {
                // 三数之和大于 0 ,右指针左移
                if (nums[i] + nums[left] + nums[right] > 0)
                {
                    right--;
                }
                // 三数之和小于 0 ,左指针右移
                else if (nums[i] + nums[left] + nums[right] < 0)
                {
                    left++;
                }
                else
                {
                    // 三数之和等于0
                    ret.push_back({nums[i], nums[left], nums[right]});
                    // 此时,在进行去重操作
                    // 去重操作,过滤掉相邻且相等的元素
                    // 去重逻辑应该放在找到一个三元组之后

                    while (right > left && nums[right] == nums[right - 1])
                    {
                        // 去除右指针相同的元素
                        right--;
                    }
                    while (right > left && nums[left] == nums[left + 1])
                    {
                        // 去除左指针相同的元素
                        left++;
                    }

                    right--;
                    left++;
                }
            }
        }

        return ret;
    }
};