2sum、3sum、4sum

这类问题,要先将数组进行排序,然后用夹逼法则(首尾指针)。最终都可以化解为2sum的问题,但是要注意过程中的去重步骤。
leetcode题目:

2SUM
思路一:将数组排好序后,使用前后指针。时间复杂度是 O ( n l o g n ) O(nlogn) O(nlogn),主要在于排序的时间。
思路二:建立map

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        map<int, int> m;
        vector<int> ans;
        for(int i=0;i<nums.size();i++){
            if(m.count(target-nums[i])!=0){      
                ans.push_back(m[target-nums[i]]);
                ans.push_back(i);
                return ans;
            }
            else{
                m[nums[i]]=i;
            }
        }
        return ans;
    }
};

// 这道题需要返回下标 因此不采用排序了

3SUM
思路:通过外层循环确定一个数,然后剩下的就是寻找和为target-nums[i]的2SUM问题。
难点是如何去重,详见下面代码的注释。时间复杂度是 O ( n 2 ) O(n^2) O(n2)

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        int n = nums.size();
        vector<vector<int>> ans;
        int target, left, right;
        
        for(int i=0;i<n;i++){
            if(i>0 && nums[i]==nums[i-1])   // 为了去重
                continue;
            if( nums[i]>0 ) break;   // 此时没有必要再进行下去了
            target = 0-nums[i];
            left = i+1;
            right = n-1;
            while(left < right){
                if(nums[left]+nums[right]==target){
                    vector<int> tmp;
                    tmp.push_back(nums[i]);
                    tmp.push_back(nums[left]);
                    tmp.push_back(nums[right]);
                    ans.push_back(tmp);
                    
                    // 为了去重
                    int val1 = nums[left];
                    while(left < right && nums[left]==val1)
                        left++;
                    int val2 = nums[right];
                    while(left < right && nums[right]==val2)
                        right--;
                    
                }else if(nums[left]+nums[right]>target){
                    right--;
                }else {
                    left++;
                }
            }
            
        }
        return ans;
    }
};

3SUM Closest

class Solution {
public:
    int threeSumClosest(vector<int>& nums, int target) {
        int n = nums.size();
        sort(nums.begin(),nums.end());
        int ans = nums[0]+nums[1]+nums[2];    // 先给ans赋一个初始值
        int left,right;
        for(int i=0;i<n;i++){
            if(i>0 && nums[i]==nums[i-1])     // 不想做没有必要的计算
                continue;
            left = i+1;
            right = n-1;
            while(left<right){
                if( nums[left]+nums[right]+nums[i]==target){
                    return target;
                }
                if( abs(nums[left]+nums[right]+nums[i]-target) < abs(ans-target))
                    ans = nums[left]+nums[right]+nums[i];
                if(nums[left]+nums[right]+nums[i]>target){
                    right--;
                }else {
                    left++;
                }
            }
                
        }
        return ans;
    }
};

3Sum With Multiplicity

class Solution {
public:
    int threeSumMulti(vector<int>& A, int target) {
        int n = A.size();
        sort(A.begin(),A.end());
        int left, right;
        int mod = 1e9+7;
        int ans = 0;
        for(int i=0;i<n;i++){
            left = i+1;
            right = n-1;
            while(left < right){
                if(A[i]+A[left]+A[right]==target){
                    if(A[left]==A[right]){
                        ans += ((right-left)*(right-left+1)/2)%mod;
                        ans = ans%mod;
                        break;
                    }else {
                        left++;
                        right--;
                        int cnt1=1,cnt2=1;
                        while(left<=right && A[left]==A[left-1]){
                            left++;
                            cnt1++;
                        }
                        while(left<=right && A[right]==A[right+1]){
                            right--;
                            cnt2++;
                        }
                        ans += (cnt1*cnt2)%mod;
                        ans = ans%mod;
                        
                    }                    
                }else if(A[i]+A[left]+A[right]>target){
                    right--;
                }else {
                    left++;
                }
            }
            
        }
        return ans;
        
    }
};

4SUM
思路一:通过循环遍历确定第一个数,然后解决剩下的3SUM问题。时间复杂度 O ( n 3 ) O(n^3) O(n3)

class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        int n= nums.size();
        sort(nums.begin(),nums.end());
        vector<vector<int>> ans;
        int left, right;
        for(int i=0;i<n;i++){
            if(i>0 && nums[i]==nums[i-1]) // 去重
                continue;
            for(int j=i+1;j<n;j++){
                if(j>i+1 && nums[j]==nums[j-1])   // 去重
                    continue;  
                left = j+1;
                right = n-1;
                while(left < right){
                   if( nums[i]+nums[j]+nums[left]+nums[right]==target){
                       vector<int> tmp;
                       tmp.push_back(nums[i]);
                       tmp.push_back(nums[j]);
                       tmp.push_back(nums[left]);
                       tmp.push_back(nums[right]);
                       ans.push_back(tmp);
                       int val1 = nums[left];
                       int val2 = nums[right];
                       while(left<right && nums[left]==val1) // 去重
                           left++;
                       while(left<right && nums[right]==val2)  // 去重
                           right--;                       
                   } else if (nums[i]+nums[j]+nums[left]+nums[right] > target){
                       right--;
                   }else{
                       left++;
                   }
                }
            }
        }
        return ans;
    }
};

思路二:空间换时间,找出两个数的所有可能的和,时间复杂度是 O ( n 2 ) O(n^2) O(n2)

class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        typedef pair<int,int> pii;
        unordered_map<int, vector<pii>> m;
        sort(nums.begin(),nums.end());
        int n = nums.size();
        for(int i=0;i<n;i++){
            for(int j=i+1; j<n ;j++)
                m[nums[i]+nums[j]].push_back(make_pair(i,j));
        }
        set<vector<int>> s;
        vector<vector<int>> ans;
        for(int i=0;i<n;i++){
            for(int j=i+1;j<n;j++){
                int t = target-nums[i]-nums[j];
                if( m.count(t)!=0){
                    for(int k=0; k< m[t].size();k++){
                        if(m[t][k].first > j){
                            vector<int> tmp{nums[i],nums[j],nums[m[t][k].first],nums[m[t][k].second] };
                            s.insert(tmp);
                        }
                    }
                }
            }
        }
        set<vector<int>>:: iterator iter = s.begin();
        while(iter!=s.end()){
            ans.push_back(*iter);
            iter++;
        }
        return ans;
        
    }
};

4SUM II

class Solution {
public:
    int fourSumCount(vector<int>& A, vector<int>& B, vector<int>& C, vector<int>& D) {
        unordered_map<int, int> m;
        int nA = A.size();
        int nB = B.size();
        int nC = C.size();
        int nD = D.size();
        for(int i=0;i<nA;i++){
            for(int j=0;j<nB;j++)
                m[A[i]+B[j]]++;
        }
        int cnt = 0 ;
        for(int i=0;i<nC;i++){
            for(int j=0; j<nD; j++){
                if( m.count(0-C[i]-D[j])!=0){
                    cnt += m[0-C[i]-D[j]];
                }
            }
        }
        return cnt;
        
    }
};

K SUM

https://segmentfault.com/a/1190000004984393
https://www.lintcode.com/problem/k-sum/description

class Solution {
public:
    /**
     * @param A: An integer array
     * @param k: A positive integer (k <= length(A))
     * @param target: An integer
     * @return: An integera
     */
    int kSum(vector<int> &A, int k, int target) {
        // write your code here
         int n = A.size();
        int dp[n+1][k+1][target+1];
        for(int i=0;i<=n;i++){
            for(int j=0;j<=k;j++){
                for(int h=0;h<=target;h++)
                   dp[i][j][h]=0;
            }
        }
        
        for(int i=0; i< n+1; i++)
         dp[i][0][0]=1;
        for(int i=1; i< n+1; i++){
            for(int j=1; j<=k && j<=i ; j++){
                for(int h=1; h<=target;h++){
                    dp[i][j][h] = dp[i-1][j][h];
                    if( A[i-1]<=h)
                    dp[i][j][h] += dp[i-1][j-1][h-A[i-1]];
                }
            }
        }
        return dp[n][k][target];
    }
};


[1] https://blog.csdn.net/haolexiao/article/details/70768526
[2] https://www.cnblogs.com/hankunyan/p/9881230.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值