18. 四数之和

题目来源:18. 四数之和

解题思路

本题使用双指针法进行解题,首先我们从起始位置为0和1的地方,嵌套遍历数组,分别代表a,b的下标。然后使用双指针一头一尾进行移动,头尾指针分别代表c,d的下标。如果当前a,b,c,d和比目标值target大,则移动尾指针,否则移动头指针。

难点分析

本题难点在于去重,题目给出的样例中有:nums = [2,2,2,2,2], target = 8,可以发现,元素本身是重复的,我们最终的答案只能是唯一的,即:[[2,2,2,2]],换言之,每一个元素只能被取一次。
再看这个例子:nums = [2,2,1,3,4],target = 10 这里的正确答案是:[[1,2,3,4]]而不是[[1,2,3,4],[1,2,3,4]],因为如果2被取两次,则结果集重复。

小结一下,对于本题可能存在三两种重复的情况:

  1. 元素本身重复
  2. a,b,c,d 之间重复取值
  3. 结果集重复

如何避免结果集重复呢?只需要避免前两条即可,所以重点在于如何避免重复对a,b,c,d取值和如何对跳过重复元素只选一次。

对于上述两个难点,我们可以先对nums进行排序,这样重复的元素就是相邻的,我们判断相邻是否相等即可,避免a,b,c,d之间是否重复也是同理。

具体代码实现中需要注意的点

  1. nums必须先排序后遍历
  2. 在取abcd的时候需要判断下标是否越界。
  3. 取值过程中的去重是当前下标向后比较,取结果集后的去重则相反。

代码实现

class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        long sum = 0;
        vector<vector<int>> result;
        sort(nums.begin(), nums.end());

        for(int i = 0;i < nums.size() ;i++)
        {
            if(i > 0 && nums[i] == nums[i - 1]) 
                continue;
            int a = nums[i];

            for(int j = i + 1 ;j < nums.size();j++)
            {
                if(j > i + 1 && nums[j] == nums[j - 1]) 
                    continue;

                int b = nums[j];

                int left = j + 1;
                int right = nums.size() - 1;

                while(left < right)
                {

                    if(left > j + 1 && nums[left] == nums[left - 1])
                    {
                        left++;
                        continue;
                    }
                    int c = nums[left];
                    if(right < nums.size() - 1 && nums[right] == nums[right + 1])
                    {
                        right--;
                        continue;
                    }
                    int d = nums[right];
                    sum = (long)a + b + c + d;

                    if(sum == target)
                    {
                        result.push_back({a,b,c,d});

                        while(left < right && nums[left] == nums[left + 1])
                        {
                            left++;
                        }
                        left++;

                        while(left < right && nums[right] == nums[right - 1])
                        {
                            right--;
                        }
                        right--;
                    }
                    else if(sum < target)
                    {
                        left++;
                    }
                    else
                    {
                        right--;
                    }

                }
            }

        }
        return result;

    }
};
posted @ 2023-03-21 09:08  蠢蛋快跑  阅读(31)  评论(0)    收藏  举报