3sum、3Sum closet、 4sum

1. 3Sum

【题目】

Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.

Note:

  • Elements in a triplet (a,b,c) must be in non-descending order. (ie, a ≤ b ≤ c)
  • The solution set must not contain duplicate triplets.

    For example, given array S = {-1 0 1 2 -1 -4},

    A solution set is:
    (-1, 0, 1)
    (-1, -1, 2)
【解析】

K Sum问题是一个系列,博客 http://tech-wonderland.net/blog/summary-of-ksum-problems.html 总结得比较完整,有兴趣可以去看。

排序之后,我们就可以对数组用两个指针分别从前后两端向中间扫描了,如果是 2Sum,我们找到两个指针之和为target就OK了,那 3Sum 类似,我们可以先固定一个数,然后找另外两个数之和为第一个数的相反数就可以了。

代码不难,先看了再说。

class 3Sum{
public:
    void twoSum(vector<vector<int>> &ret, vector<int> &nums, int begin, int target)
    {
        int l=begin;
        int r=nums.size()-1;
        while(l<r)//分别从前面和后面向中间走,从而保证最后产生的数据集一定是从小到大排序的
        {
            if(nums[l]+nums[r]+target==0)
            {
                vector<int> line;
                line.push_back(target);
                line.push_back(nums[l]);
                line.push_back(nums[r]);
                ret.push_back(line);
                while(l<r && nums[l]==nums[l+1]) l++;//去重
                while(l<r && nums[r]==nums[r-1]) r--;<span style="font-family: Arial;">//去重</span>
                l++;
                r--;
            }
            else if(nums[l]+nums[r]+target<0)
                l++;
            else
                r--;
        }
    }

    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> ret;
        if(nums.size()<=2)
            return ret;
            
        int target;
        sort(nums.begin(), nums.end());
        
        twoSum(ret, nums, 1, nums[0]);
        for(int i=1; i<nums.size()-2; i++)//注意,这里需要保证后面的数据至少有两个才可以进行下面的操作
        {
            if(nums[i]>0)
                break;
            if(nums[i]==nums[i-1])
                continue;
            else
                twoSum(ret, nums, i+1, nums[i]);
        }
        return ret;
    }
};


注意,对于 num[i],寻找另外两个数时,只要从 i+1 开始找就可以了。

这种写法,可以避免结果集中有重复,因为数组时排好序的,所以当一个数被放到结果集中的时候,其后面和它相等的直接被跳过。

2. 3Sum closet

Given an array S of n integers, find three integers in S such that the sum is closest to a given number, target. Return the sum of the three integers. You may assume that each input would have exactly one solution.

    For example, given array S = {-1 2 1 -4}, and target = 1.

    The sum that is closest to the target is 2. (-1 + 2 + 1 = 2).

class 3SumCloset{
public:
    int towSumCloset(vector<int> & nums, int begin, int curData, int target)
    {
        int l=begin;
        int r=nums.size()-1;
        int closet=nums[l]+nums[r]+curData;
        while(l<r)
        {
            int tmp=nums[l]+nums[r]+curData;
            if(tmp==target)
                return tmp;
            else if(tmp<target)
            {
                if(abs(tmp-target) < abs(closet-target))
                    closet=tmp;
                while(l<r && nums[l]==nums[l+1]) l++;
                l++;
            }
            else
            {
                if(abs(tmp-target) < abs(closet-target))
                    closet=tmp;
                while(l<r && nums[r]==nums[r-1]) r--;
                r--;
            }
        }
        return closet;
    }

    int threeSumClosest(vector<int>& nums, int target) {
        int closetTarget=nums[0]+nums[1]+nums[2];
        int twoRet;
        int len=nums.size();
        sort(nums.begin(), nums.end());
        for(int i=0; i<len-2; i++)//或许前面的题目这里不是重点,但在此处必须保证i后面有两个元素或以上,否则会出错
        {
            if(i>0 && nums[i]==nums[i-1])
                continue;
            twoRet=towSumCloset(nums, i+1, nums[i], target);
            if(twoRet==target)
                return target;
            else
            {
                if(abs(target-closetTarget) > abs(target-twoRet))
                    closetTarget=twoRet;
            }
        }
        return closetTarget;
    }
};

3. 4sum问题

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)
解析:

4sum问题甚至到ksum都可以用改方法一步的完善,只是,写函数时,要将4,5,6,等用参数的形式传进去就可以了

class fourSum{
public:

    int len;
    vector<int> line;//这里自己定义了line,可以减少成员函数的参数个数

    void TwoSum(vector<vector<int>> & ret, vector<int> & nums, int begin, int target){
        int l=begin;
        int r=len-1;
        while(l<r){
            if(nums[l]+nums[r]==target){
                line[2]=nums[l];
                line[3]=nums[r];
                ret.push_back(line);
                while(l<r && nums[l+1]==nums[l]) l++;
                while(l<r && nums[r]==nums[r+1]) r--;
                l++;
                r--;
            }   
            else if(nums[l]+nums[r]<target)
                l++;
            else
                r--;
        }
    }
    
    void ThreeSum(vector<vector<int>> & ret, vector<int> & nums, int begin, int target){
        for(int i=begin; i<len-2; i++){
            if(i>begin && nums[i]==nums[i-1])
                continue;
            line[1]=nums[i];
            TwoSum(ret, nums, i+1, target-nums[i]);
        }
    }

    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        vector<vector<int>> ret;
        if(nums.size()<4)
            return ret;
            
        line.resize(4);
        len=nums.size();
        sort(nums.begin(), nums.end());
        
        for(int i=0; i<nums.size()-3; i++){
            if(i>0 && nums[i]==nums[i-1])
                continue; 
            else{
                line[0]=nums[i];
                ThreeSum(ret, nums, i+1, target-nums[i]);
            }
        }
        return ret;
    }
};
更经典的解法见:http://tech-wonderland.net/blog/summary-of-ksum-problems.html

class Solution {
02 public:
03     vector< vector > findZeroSumInSortedArr(vector &num, int begin, int count, inttarget)
04     {
05         vector ret;
06         vector tuple;
07         set visited;
08         if (count == 2)
09         {
10             int i = begin, j = num.size()-1;
11             while (i < j)
12             {
13                 int sum = num[i] + num[j];
14                 if (sum == target && visited.find(num[i]) == visited.end())
15                 {
16                     tuple.clear();
17                     visited.insert(num[i]);
18                     visited.insert(num[j]);
19                     tuple.push_back(num[i]);
20                     tuple.push_back(num[j]);
21                     ret.push_back(tuple);
22                     i++; j–;
23                 }
24                 else if (sum < target)
25                 {
26                     i++;
27                 }
28                 else
29                 {
30                     j–;
31                 }
32             }
33         }
34         else
35         {
36             for (int i=begin; i<num.size(); i++)
37             {
38                 if (visited.find(num[i]) == visited.end())
39                 {
40                     visited.insert(num[i]);
41                     vector subRet = findZeroSumInSortedArr(num, i+1, count-1, target-num[i]);
42                     if (!subRet.empty())
43                     {
44                         for (int j=0; j<subRet.size(); j++)
45                         {
46                             subRet[j].insert(subRet[j].begin(), num[i]);
47                         }
48  
49                         ret.insert(ret.end(), subRet.begin(), subRet.end());
50                     }
51                 }
52             }
53         }
54  
55         return ret;
56     }
57  
58     vector threeSum(vector &num) {
59         sort(num.begin(), num.end());
60         return findZeroSumInSortedArr(num, 0, 3, 0);
61     }
62  
63     vector fourSum(vector &num, int target) {
64         sort(num.begin(), num.end());
65         return findZeroSumInSortedArr(num, 0, 4, target);
66     }
67 };



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值