3Sum, 3Sum Closest, 4 Sum

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)

暴力拆解的方法对数组进行遍历可以找到所有的。但尝试之后发现,去重是个很麻烦的事,重复的结果很难筛掉。
解决此题,首先要对数组进行排序。然后固定一个数,用两个下边从数组的两端进行遍历。减小算法复杂度。同时,还要从以下几个方面减小算法运行时间。
(1)原数组不够3个值返回空。
(2)固定一个值。遍历的下标范围从0到nums.size()-2,数组已排序,所以要满足nums[i]<=0。
(3)对于同一个固定值。要考虑多解的情况。我们用两个循环来处理。
(4)不满足条件则让左右下标向中间移动。

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> result;
        int a=0,b=0,c=0;
        sort( nums.begin() , nums.end() );
        if(nums.size()<3)
            return result;

        for(int i=0;i<nums.size()-2 && nums[i]<=0;i++){
            int l=i+1;
            int r=nums.size()-1;
            int sum=0;
            if(i>0 && nums[i]==nums[i-1])
                continue;
            while(l<r){
                sum=nums[i]+nums[l]+nums[r];
                if(sum==0){
                    vector<int> n;
                    n.push_back(nums[i]);
                    n.push_back(nums[l]);
                    n.push_back(nums[r]);
                    result.push_back(n);
                    //处理同一个固定值多解的情况,同时可以省略不必要的比较
                    while (++l < r  && nums[l-1] == nums[l]);  
                    while (--r > l && nums[r+1] == nums[r]);  
                }
                else if(sum<0)
                    l++;
                else if(sum>0)
                    r--;
            }
        }
        return result;
    }

};
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).

这个问题的考虑方法和3Sum一样。还是对数组进行排序。固定一个值,然后从数组的两端取值逼近。不同之处在于,我们要找的是距离target最近的值,因此不用再记录每次的结果,只需要保留最近的值就可以了。当sum==target时,已经是最近的结果,直接返回即可。编码过程中,有一个问题是需要注意的,就是sum的初始取值。由于target未知,不能随意给sum赋一个常数,因为可能存在初始的sum就跟target相等的情况,造成算法得出错误的结果。所以。我给sum赋的初值是while循环第一次运行时tmp的值。这样以来就能保证算法的正确运行。

class Solution {
public:
    int threeSumClosest(vector<int>& nums, int target) {
        sort(nums.begin(),nums.end());
        int sum=nums[0]+nums[1]+nums[nums.size()-1];
        int tmp=0;
        for(int i=0;i<nums.size()-1;i++){
            int l=i+1;
            int r=nums.size()-1;
            while(l<r){
                tmp=nums[i]+nums[l]+nums[r];
                if(tmp==target)
                    return tmp;
                else if(tmp>target){
                    if(abs(sum-target)>abs(tmp-target))
                        sum=tmp;
                    r--;
                }
                else if(tmp<target){
                    if(abs(sum-target)>abs(tmp-target))
                        sum=tmp;
                    l++;
                }
            }
        }
        return sum;
    }
};
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:
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)

4 Sum的问题,本来考虑就是在3 Sum的基础上多一层循环,固定两个数,然后从数组两头开始检索。但在实际测试中,有个问题实在头疼,那就是去重!!!加一层循环固定两个数,很难保证这两个数的组合不会出现重复。期间试了很多方法,包括设置i和j需要跳过的情况,以及与前一个插入的数组比较的策略,都不能完全保证重复数字的出现。然后又尝试外层固定的两个数也采用从数组两端向中间压缩的策略。代码重复度很大,而且这种方法会反过来缺少一些情况。所以,最后还是采用了在结果中去重,重新排序result,并用unique()函数去重,通过测试,代码如下:

class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        sort(nums.begin(),nums.end());
        vector<vector<int>> result;

        if(nums.size()<4)
            return result;

        if(nums.size()==4){
            if(nums[0]+nums[1]+nums[2]+nums[3]==target)
                result.push_back(nums);
            return result;
        }
        for(int i=0;i<nums.size()-3;i++){
            for(int j=i+1;j<nums.size()-2;j++){
                int l=j+1;
                int r=nums.size()-1;
                while(l<r){
                    int sum=nums[i]+nums[j]+nums[l]+nums[r];
                    if(sum==target){
                        vector<int> tmp;
                        tmp.push_back(nums[i]);
                        tmp.push_back(nums[j]);
                        tmp.push_back(nums[l]);
                        tmp.push_back(nums[r]);
                        result.push_back(tmp);
                        while(++l<r && nums[l]==nums[l-1]);
                        while(l<--r && nums[r]==nums[r+1]);
                    }
                    else if(sum<target)
                        l++;
                    else if(sum>target)
                        r--;
                }
            }
        }
        sort(result.begin(),result.end());
        result.erase( unique( result.begin(), result.end() ), result.end());
        return result;
    }

};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
#include <stdio.h> #include <string.h> #include <stdlib.h> typedef struct { int no; char info; } VertexType; typedef struct { int edges[MAXV][MAXV]; int n, e; VertexType vexs[MAXV]; } MatGraph; void CreatMat(MatGraph &g, int A[MAXV][MAXV], int n, int e) { int i, j; g.n = n; g.e = e; for (i = 0; i < g.n; i++) for (j = 0; j < g.n; j++) g.edges[i][j] = A[i][j]; } void DispMat(MatGraph g) { int i, j; for (i = 0; i < g.n; i++) { for (j = 0; j < g.n; j++) if (g.edges[i][j] != INF) printf("%4d", g.edges[i][j]); else printf("%4s", "∞"); printf("\n"); } } int Prim(MatGraph g, int v) { int lowcost[MAXV], min, n = g.n, sum; int closest[MAXV], i, j, j; for (i = 0; i < n; i++) { lowcost[i] = g.edges[v][i]; closest[i] = v; } for (i = 1; i < n; i++) { min = INF; for (j = 0; j < n; j++) if (lowcost[j] != 0 && lowcost[j] < min) { min = lowcost[j]; k = j; } printf("\n 城市%d和城市%d之间的最短距离为:%d\n", closest[k] + 1, k + 1, min * 10); sum = sum + min; lowcost[k] = 0; for (j = 0; j < n; j++) if (g.edges[k][j] != 0 && g.edges[k][j] < lowcost[j]) { lowcost[j] = g.edges[k][j]; closest[j] = k; } } return sum; } int main() { int v = 3, k; MatGraph g; int A[MAXV][MAXV] = { {0, 6, 1, 5, INF, INF}, {6, 0, 5, INF, 3, INF}, {1, 5, 0, 5, 6, 4}, {5, INF, 5, 0, INF, 0, 6}, {INF, 3, 6, INF, 0, 6}, {INF, INF, 4, 2, 6, 0} }; int n = 6, e = 10; CreateMat(g, A, n, e); printf("城市连接图的邻接矩阵:\n"); DispMat(g); printf("\n普利姆算法求解结果:\n"); k = Prim(g, 0); printf("\n各个城市之间的总最短距离为:%d千米\n", k * 10); return 1; }改bug
06-10
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值