算法设计与分析(12)-- 4Sum(难度:Medium)

算法设计与分析(12)

题目:4Sum

问题描述:Given an array S of n integers, are there elements a, b, c, and d in S such that a + b + c + d = target? Find all unique quadruplets in the array which gives the sum of target.

Note: The solution set must not contain duplicate quadruplets.

For example, given array S = [1, 0, -1, 0, -2, 2], and target = 0.

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

算法思路:

由于之前已经做过了2Sum和3Sum的题目了,所以这里的算法也就是可以直接基于3Sum,然后再给一些细节优化,就可以得到一个比较高效的算法。给定一个动态数组vector<int>& nums和目标值int target,我们需要从数组中找到i1,i2,i3,i4,满足nums[i1]+nums[i2]+nums[i3]+nums[i4]=target.
(1)首先,若数组长度小于4直接返回空的答案,否则,使用sort()函数对数组nums进行排序:

int len = nums.size();
vector<vector<int>> result;
if (nums.size() < 4)    return result;
sort(nums.begin(), nums.end());

(2)使用for循环遍历i1:

for (int i1 = 0; i1 < len - 3; ++i1)

(3)这里我们可以考虑优化操作,即当nums[i1] + nums[i1 + 1] + nums[i1 + 2] + nums[i1 + 3] > target,此时无论i2、i3、i4如何取值都不会满足条件,所以可以直接使用break语句;当nums[i1] + nums[len - 3] + nums[len - 2] + nums[len - 1] < target,此时只能继续增大i1,所以可以使用continue语句:

if (nums[i1] + nums[i1 + 1] + nums[i1 + 2] + nums[i1 + 3]>target) break;
if (nums[i1] + nums[len - 3] + nums[len - 2] + nums[len - 1]<target) continue;

(4)接着在i1的循环内,使用for循环遍历i2:

for (int i2 = i1 + 1; i2 < len - 2; ++i2)

(5)同样参考第(3)步的优化方法:

if (nums[i1] + nums[i2] + nums[i2 + 1] + nums[i2 + 2]>target) break;
if (nums[i1] + nums[i2] + nums[len - 2] + nums[len - 1]<target) continue;

(6)有了i1、i2,然后就是基于2Sum的算法求解,并且使用函数isExist()判断result内是否有重复的结果,若没有则把结果存于result中:

int i3 = i2 + 1, i4 = len - 1;
while (i3 < i4)
{
    if (nums[i1] + nums[i2] + nums[i3] + nums[i4] < target) ++i3;
    else if (nums[i1] + nums[i2] + nums[i3] + nums[i4] > target) --i4;
    else
    {
        vector<int> tmp; tmp.push_back(nums[i1]); tmp.push_back(nums[i2]); tmp.push_back(nums[i3]); tmp.push_back(nums[i4]);
        if (result.empty()) result.push_back(tmp);
        else if(!isExist(result,tmp)) result.push_back(tmp);
        ++i3; --i4;
    }
}

(7)最后返回结果:return result;

实现代码:

#include<iostream>
#include<vector>
#include<algorithm>

using namespace std;

bool isExist(vector<vector<int>>& result, vector<int> &tmp)
{
    for (int i = 0; i < result.size(); ++i)
        if (result[i] == tmp) return true;
    return false;
}

vector<vector<int>> fourSum(vector<int>& nums, int target) 
{
    int len = nums.size();
    vector<vector<int>> result;
    if (nums.size() < 4)    return result;
    sort(nums.begin(), nums.end());
    for (int i1 = 0; i1 < len - 3; ++i1)
    {
        if (nums[i1] + nums[i1 + 1] + nums[i1 + 2] + nums[i1 + 3]>target) break;
        if (nums[i1] + nums[len - 3] + nums[len - 2] + nums[len - 1]<target) continue;
        for (int i2 = i1 + 1; i2 < len - 2; ++i2)
        {
            if (nums[i1] + nums[i2] + nums[i2 + 1] + nums[i2 + 2]>target) break;
            if (nums[i1] + nums[i2] + nums[len - 2] + nums[len - 1]<target) continue;
            int i3 = i2 + 1, i4 = len - 1;
            while (i3 < i4)
            {
                if (nums[i1] + nums[i2] + nums[i3] + nums[i4] < target) ++i3;
                else if (nums[i1] + nums[i2] + nums[i3] + nums[i4] > target) --i4;
                else
                {
                    vector<int> tmp; tmp.push_back(nums[i1]); tmp.push_back(nums[i2]); tmp.push_back(nums[i3]); tmp.push_back(nums[i4]);
                    if(!isExist(result,tmp)) result.push_back(tmp);
                    ++i3; --i4;
                }
            }
        }
    }
    return result;
}

int main()
{
    int arr[] = { 1, 0, -1, 0, -2, 2 }, target = 0;
    vector<int> nums(arr, arr + 6);
    vector<vector<int>> result;
    result = fourSum(nums, target);

    for (int i = 0; i < result.size(); ++i)
    {
        for (int j = 0; j < result[i].size(); ++j)
            cout << result[i][j] << " ";
        cout << endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值