【算法专题】双指针算法之18. 四数之和(力扣)

 欢迎来到 CILMY23的博客

🏆本篇主题为:双指针算法之18. 四数之和(力扣)

🏆个人主页:CILMY23-CSDN博客

🏆系列专栏:Python | C++ | C语言 | 数据结构与算法 | 贪心算法 | Linux | 算法专题 | 代码训练营

🏆感谢观看,支持的可以给个一键三连,点赞收藏+评论。如果你觉得有帮助,还可以点点关注


题目:

18. 四数之和 - 力扣(LeetCode)

给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):

  • 0 <= a, b, c, d < n
  • abc 和 d 互不相同
  • nums[a] + nums[b] + nums[c] + nums[d] == target

你可以按 任意顺序 返回答案 。

题目解析:

 这道题在有二数之和和三数之和的前提上,理解起来是比较快的。

1.给了一个目标值target

2.不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] 

3.找出不重复的四元组

  • 0 <= a, b, c, d < n
  • abc 和 d 互不相同
  • nums[a] + nums[b] + nums[c] + nums[d] == target

算法原理:

 个人感觉:感觉四数之和比三数之和难多了

首先根据前两题的经验,我们很快就能推算出,这是一题双指针算法的题目,大致思路还是跟之前一样,双指针求和,然后去重。

所以我们能写出如下代码:

class Solution
{
public:
    static vector<vector<int>> fourSum(vector<int>& nums, int target)
    {
        vector<vector<int>> ret;
        //排序数组
        sort(nums.begin(), nums.end());
        int k = nums.size() - 1; //固定k
        for (k = nums.size() - 1; k > 2;)
        {
            for (int j = k - 1; j > 1;)
            {
                int sum1 = nums[k] + nums[j];
                int left = 0;
                int right = j - 1;
                while (left < right)
                {
                    int sum2 = nums[left] + nums[right];
                    if (sum2 + sum1 == target)
                    {
                        ret.push_back({ nums[left],nums[right],nums[j],nums[k] });
                        left++;
                        right--;
                    }
                    else if (sum2 > (target - sum1))
                    {
                        right--;
                    }
                    else if (sum2 < (target - sum1))
                    {
                        left++;
                    }
                }
            }
        }
        return ret;
    }
};

第一个,我用一个sum1进行存储两个固定的数的值,sum2存储两个指针的值。

接下来是重点,我的两个指针和两个固定的值相加要和target一样,所以两个指针的值要和target-sum1进行比较。

 这个很重要,我当时和sum1比较发现是行不通的,没把target搞进去,因为我们最终是要和target目标值进行比较的。

接下来是去重,首先,是两个指针的去重,这个相对容易一些。

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

其次是两个固定数的去重,由于我这次去重将放在循环的末尾了,所以会有一些变化。

for (k = nums.size() - 1; k > 2;)
{
    for (int j = k - 1; j > 1;)
    {
        //......
        while (left < right)
        {
            //......
        }
        j--;
        //j去重
        while (j > 1 && nums[j + 1] == nums[j])
        {
            j--;
        }
    }
    k--;
    //k去重
    while (k > 2 && nums[k + 1] == nums[k])
    {
        k--;
    }
}

 去重前,先保证固定的数会走到下一个位置,然后再进行比较。

然后还有一个坑的点是这题

会出现一个数值过大的问题,所以要把sum1和sum2都改成long long即可。 

代码编写:

class Solution
{
public:
    static vector<vector<int>> fourSum(vector<int>& nums, int target)
    {
        vector<vector<int>> ret;
        //排序数组
        sort(nums.begin(), nums.end());
        int k = nums.size() - 1; //固定k
        for (k = nums.size() - 1; k > 2;)
        {
            for (int j = k - 1; j > 1;)
            {
                long long int sum1 = nums[k] + nums[j];
                int left = 0;
                int right = j - 1;
                while (left < right)
                {
                    long long int sum2 = nums[left] + nums[right];
                    if (sum2 + sum1 == target )
                    {
                        ret.push_back({ nums[left],nums[right],nums[j],nums[k] });
                        left++;
                        right--;
                        while (left < right && nums[left - 1] == nums[left])
                        {
                            left++;
                        }
                        while (left < right && nums[right + 1] == nums[right])
                        {
                            right--;
                        }
                    }
                    else if (sum2 > (target-sum1))
                    {
                        right--;
                    }
                    else if (sum2 < (target-sum1))
                    {
                        left++;
                    }
                }
                j--;
                //j去重
                while (j > 1 && nums[j + 1] == nums[j])
                {
                    j--;
                }
            }
            k--;
            //k去重
            while (k > 2 && nums[k + 1] == nums[k])
            {
                k--;
            }
        }
        return ret;
    }
};

🛎️感谢各位同伴的支持,本期C++算法专题就讲解到这啦,下期我们将详解滑动窗口知识点,如果你觉得写的不错的话,可以给个一键三连,点赞,收藏+评论,可以的话还希望点点关注,若有不足,欢迎各位在评论区讨论。    

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值