leecode_18 4Sum (k Sum)

Given an array S of n integers, are there elements abc, 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:

  • Elements in a quadruplet (a,b,c,d) must be in non-descending order. (ie, a ≤ b ≤ c ≤ d)
  • 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)

本题固然可以用一堆if-else来解决,但是为了找到k个数的和的通用解法,固不采用if-else嵌套的方法。

初步设想是先排序,然后用BFS来解决,但是考虑到有重复的数字,单纯BFS会导致输出的集合中有重复,所以要对BFS做些变换(c++描述):

首先队列的元素类型为pair<vector<int>,int>,  vector<int>为当前的序列,而int则为最后一个元素的index;

如此,只要遇到重复的元素,所有的int都为重复的元素的最后一个元素的index,如{0,0,0},则生成三个pair压入队列中,即

( {0}, 2 )    ( { 0,0 }, 2)  ( {0,0,0}, 2 )

如此,就不会出现  ( {0},0 )  ( {0}, 1 )  ( {0,0} ,1)  ( {0,0}, 2)  ( {0,0},2), 从而避免输出中重复项的计算

附上c++代码实现,还有优化的空间 :)

#include <iostream>
#include <string>
#include <unordered_map>
#include <queue>
#include <unordered_set>
using namespace std;

vector<vector<int>> fourSum(vector<int>& nums, int target) {
    int k=4;
    vector<vector<int>> res;
    queue< pair< vector<int>,int > > que;
    sort(nums.begin(),nums.end());
    //ini
    for (int i=0;i<nums.size();i++){
     int low_bound=lower_bound(nums.begin(), nums.end(),nums[i])-nums.begin();
     int up_bound=upper_bound(nums.begin(),nums.end(),nums[i])-nums.begin();
        vector<int> temp;
        for (int i=low_bound;i<up_bound;i++){
            temp.push_back(nums[i]);
            que.push(make_pair(temp,up_bound-1));
        }
        i=up_bound-1;
    }
    
    while(!que.empty()){
        vector<int> vec=que.front().first;
        int index=que.front().second;
        que.pop();
        //cout<<endl;
        int sum=0;
        for (int i=0;i<vec.size();i++)
            sum+=vec[i];
        if (vec.size()==k && sum==target){
            res.push_back(vec);
            continue;
        }
            
        if (vec.size()==k-1 && index<=nums.size()-2)
            for (int i=index+1;i<nums.size();i++){
               if (sum+nums[i]==target){
                     vec.push_back(nums[i]);
                     res.push_back(vec);
                     break;
                 }
                continue;
            }
        
        if (vec.size()<k-1 && index<=nums.size()-2){
            int temp=sum;
            vector<int> v_temp=vec;
            for (int i=index+1;i<nums.size();i++){
                int p=nums[i];
                int low_bound=lower_bound(nums.begin(), nums.end(),p)-nums.begin();
                int up_bound=upper_bound(nums.begin(),nums.end(),p)-nums.begin();
            
                for (int i=low_bound;i<up_bound;i++){
                     sum+=nums[i];
                     vec.push_back(nums[i]);
                    if (vec.size()<=k){
//                        for (int j=0;j<vec.size();j++)
//                            cout<<vec[j]<<" ";
//                        cout<<endl;
                        que.push(make_pair(vec,up_bound-1));
                    }
                    
                }
                vec=v_temp;
                sum=temp;
                i=up_bound-1;
           }
     }
  
    }
 
    return res;
}

int main(){
    vector<int> vec1={1,0, -1, 0, -2, 2};
    
    vector<vector<int>> res=fourSum(vec1,0);
    
    for (int i=0;i<res.size();i++){
        for(int j=0;j<res[i].size();j++)
            cout<<res[i][j]<<" ";
        cout<<endl;
            }
    
    
    return 0;
    
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值