Leetcode:18. 四数之和(C++)

目录

问题描述:

实现代码:


问题描述:

给你一个由 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:

输入:nums = [1,0,-1,0,-2,2], target = 0
输出:[[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]
示例 2:

输入:nums = [2,2,2,2,2], target = 8
输出:[[2,2,2,2]]

实现代码:

class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) 
    {
        vector<vector<int>> result;//用于返回的结果
        sort(nums.begin(),nums.end());//排序
        for(int k=0;k<nums.size();k++)
        {
            //剪枝
            if(nums[k]>target&&nums[k]>=0)
            {
                break;
            }
            //对指针k去重
            if(k>0&&nums[k]==nums[k-1])
            {
                continue;
            }
            for(int i=k+1;i<nums.size();i++)
            {
                //剪枝
                if(nums[k]+nums[i]>target&&nums[k]+nums[i]>=0)
                {
                    break;
                }
                //对指针i去重
                if(i>k+1&&nums[i]==nums[i-1])
                {
                    continue;
                }
                int left=i+1;
                int right=nums.size()-1;
                while(left<right)
                {
                    if((long)nums[k]+nums[i]+nums[left]+nums[right]>target) right--;
                    else if((long)nums[k]+nums[i]+nums[left]+nums[right]<target) left++;
                    else
                    {
                        result.push_back(vector<int>{nums[k], nums[i], nums[left], nums[right]});
                        //left去重
                        while(left<right&&nums[left]==nums[left+1]) left++;
                        //right去重
                        while(left<right&&nums[right]==nums[right-1]) right--;
                        left++;
                        right--;
                    }
                                      
                }
            }
        }
        return result;
    }
};

和三数之和的题思路一样,这里在外层多加一层循环,然后改一改一些代码细节即可。

这里最重要的还是剪枝和去重操作,下面解释一下对应的代码。

对于第一层k的剪枝:

//剪枝
if(nums[k]>target&&nums[k]>=0)
{
    break;
}

当nums[k]大于target后,由于前面已经进行过排序了,所以后面不可能再出现让其和为target的数了,至于为什么还要同时判断nums[k]>=0,因为有可能target为负数,当nums[k]已经大于target时,后面任然可以出现相加让其和更小的数,就是两个负数相加,所以这里要判断一下大于等于零。举个例子:nums={-3,-1,0,0},target=-4,当nums[1]=-3>-5时,明显是不能break的,会少收集这种情况。

对于指针k的去重:

//对指针k去重
if(k>0&&nums[k]==nums[k-1])
{
    continue;
}

当指针k指向的数与其前一个数相同时,直接continue跳出此次循环,直接进行下一次循环。这里为什么不是与其后一个数相比而是与前一个数相比呢,因为如果是和后一个数相比,会直接在第一次遇到这个数的时候就跳出循环,导致指针i指向这个数的情况没有记录到,所以这里要与前一个数相比。

对于第二层k+i的剪枝:

//剪枝
if(nums[k]+nums[i]>target&&nums[k]+nums[i]>=0)
{
    break;
}

和第一层一样的逻辑,这里就不解释了,就是罗列一下。

对于指针i的去重:

 //对指针i去重
if(i>k+1&&nums[i]==nums[i-1])
{
    continue;
}

和对于指针k的去重逻辑相同。

对于指针left和指针right去重:

//left去重
while(left<right&&nums[left]==nums[left+1]) left++;
//right去重
while(left<right&&nums[right]==nums[right-1]) right--;

当left指向的数与其后一个数相同时,向右移动left。

当right指向的数与其前一个数相同时,想左移动right。

最后left++,right--,使其指向第一个不同的数。

至于为什么不把这个两个去重条件一开始就写在while循环里呢,原因和上面i指针的一样,至少要记录一次然后再判断,全跳过去不就一次都没用这个数了么。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Cosmoshhhyyy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值