本文为两个题:【三数和(3Sum)】与【最近三数和(3Sum Closest)】问题

第一部分分析3Sum问题,第二部分分析3Sum Closest问题,由于两个问题的思路很像,所以这里放到一起分析。

其中3Sum问题好像还是计算机科学领域暂未解决的问题之一,当然,还没找到更好的解决方案。

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)

说的意思很简单,就是:给出一个整型数组,从里面找三个数 a ,b ,c 并且使 a+b+c=0 。找出所有符合条件的三元组解集。并且解集中不能出现重复的解。

Solutions

  • 1 3Sum -- 61~69ms

    • 首先是对数组进行升序排序,然后逐个选择一个整型,并从剩下的数组元素中选出两个数字,使这三个数字的和为0。
    • 选剩下的两个数字时,第二个数字从第一个数字的下一个数字开始,这是因为,第一个数字及其之前的数字都已进行过查找操作!如果有解,则一定已经找到过了。所以第二个数字从第一个数字的下一个数字开始向后选取;第三个数字从最后一个数字开始向前选取,因为数组已排序,则只要存在,必定能够找到。
    • 按这种思想的代码如下:
    class Solution {
    public:
    vector<vector<int> > threeSum(vector<int> &num) {
    vector<vector<int> > res;
    if(num.size()<3) return res;//参数检验
    sort(num.begin(),num.end()); //先排序 int beg , end , sum;
    vector<int> tmp(3,0);
    for(int i = 0;i<num.size()-2;++i){
    // 去除重复数字的再次查找,避免结果集合中出现重复解
    if(num[i]>0)break;
    if((i>0) && num[i]==num[i-1]) continue;
    beg = i + 1;
    end = num.size()-1;
    while(beg < end){
    sum=num[beg] + num[end] + num[i];
    if( sum< 0) ++beg;
    else if(sum > 0) --end;
    else{
    tmp[0] = num[i];
    tmp[1] = num[beg];
    tmp[2] = num[end];
    res.push_back(tmp);
    // 同样是去除重复数字的再次查找,避免结果集合中出现重复解
    while(beg<end && num[beg]==tmp[1]) ++beg;
    while(beg<end && num[end]==tmp[2]) --end;
    if(beg>=end) break;
    }
    }
    }
    return res;
    }
    };
    • 测试集进行测试后(博客园这里图片好像加载不出来~~):



      https://github.com/bbxytl/LeetCodesOJ/blob/master/Algorithms/15 3Sum/images/pic1.png
    • 在维基百科里有关于3Sum的说明,同时我又去查找了一下StackOverflow,发现目前只有这种复杂度为 \(O(N^2)\) 的解决方案,还没有更好的解决方法~~~,也可能是我没有找到。维基百科里说的算法思想便是上面的方法,并给出了伪代码:
    sort(S);
    for i=0 to n-3 do
    a = S[i];
    start = i+1;
    end = n-1;
    while (start < end) do
    b = S[start];
    c = S[end];
    if (a+b+c == 0) then
    output a, b, c;
    // Continue search for all triplet combinations summing to zero.
    start = start + 1
    end = end - 1
    else if (a+b+c > 0) then
    end = end - 1;
    else
    start = start + 1;
    end
    end
    end



    https://github.com/bbxytl/LeetCodesOJ/blob/master/Algorithms/15 3Sum/images/pic2.png

附录

2. 3Sum Closest

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

说的意思很简单,就是:给出一个整型数组,从里面找三个数 a ,b ,c 并且使 a+b+c=0 。找出所有符合条件的三元组解集。并且解集中不能出现重复的解。

Solutions

  • 1 3Sum Closest -- 18ms

    • 这题的思想和求 [3Sum] 的思想是类似的,因此可以使用同思想来求解。
    • 首先是对数组进行升序排序,然后逐个选择一个整型,并从剩下的数组元素中选出两个数字,求出这三个数字的和 sum
    • 选剩下的两个数字时,第二个数字从第一个数字的下一个数字开始,这是因为,第一个数字及其之前的数字都已进行过查找操作!如果有解,则一定已经找到过了。所以第二个数字从第一个数字的下一个数字开始向后选取;第三个数字从最后一个数字开始向前选取,因为数组已排序,则只要存在,必定能够找到。
    • 比较sumtarget的大小,如果相等,则说明三数和与target最近的距离是0,这种情况是极限情况,不可能还有比这更近的了,所以可直接返回此sum
    • 如果 sum != target 则判断当前两数之间的距离 dt=abs(sum-target)和目前已求得的最短距离 dis 哪个更小,如果 dt<dis ,则说明出现了一个更接近 target 的解。则记录下此解的和 res
    • 循环结束后,res 里记录的便为最接近 target 的三数和。
    • 按这种思想的代码如下:
    class Solution {
    public:
    int threeSumClosest(vector<int> &num, int target) {
    int n=num.size();
    if(n<3)return 0;
    sort(num.begin(),num.end());
    int beg,end,sum=0;
    int dis=INT_MAX;
    int res;
    for(int i=0;i<n-2;++i){
    beg=i+1;
    end=n-1;
    while(beg<end){
    sum=num[i]+num[beg]+num[end];
    if(sum==target)return sum;
    else if(sum<target) ++beg;
    else --end;
    int dt=(abs(sum-target));
    if(dis>dt){
    dis=dt;
    res=sum;
    }
    }
    }
    return res;
    }
    };
  • 2 3Sum Closest -- 15ms

    • 在共享区里,我发现了这样一种解法:
    • 我们刚才的思想是,先确定一个数字来定位,然后再遍历出剩下的两个数字。这里的思想正好是反过来的:先确定两个数字,再找剩下的一个。
    • 先对数组进行排序,定位首尾两数。然后求出新的要找的目标数字 newTarget = target - (num[start]+num[end]) ,再使用二分查找查找剩下的那个数字。使用的二分查找返回的数字是找到的比较符合条件的数组中数字的下标。
    • 二分查找方法的时间复杂度是 \(O(logN)\)
    • 根据查出的数字,求三数和 curSum ,比较其与最终要求的target的距离是否小于之间的最小距离 mindiff ,如果小于,则说明找到一个更小的解,给最小距离 mindiff 重新赋值。然后继续下一轮查找。
    • 由以上分析可知,此算法的时间复杂度是 \(O(NlogN)\) 。要优于方法1 的 \(O(N^2)\) 。
    • 下面是经我改进后的代码:
    class Solution {
    // 二分查找
    int findTarget(vector<int> &num, int start, int end, int target) {
    if (start==end) return start;
    if (end-start==1)
    return abs(num[end]-target) > abs(num[start]-target)
    ? start : end;
    int mid = (start+end)/2;
    if (num[mid]==target) return mid;
    else if(num[mid]>target)
    return findTarget(num, start, mid, target);
    else return findTarget(num, mid, end, target);
    }
    public:
    int threeSumClosest(vector<int> &num, int target) {
    int res=0;
    if(num.size()<=3){
    for(auto v : num) res+=v;
    return res;
    }
    sort(num.begin(), num.end());
    int start = 0;
    int end = int(num.size()-1);
    int mindiff = INT_MAX;
    while (start<end-1) {
    int newTarget = target - (num[start] + num[end]);
    int p = findTarget(num, start+1, end-1, newTarget);
    int curSum = num[start] + num[end] + num[p];
    if (curSum == target) {
    return target;
    }else if(curSum > target) end--;
    else start++;
    mindiff = abs(mindiff)>abs(target-curSum) ? target-curSum : mindiff;
    }
    res=target-mindiff;
    return res;
    }
    };

附录

LeetCodeOJ刷题之15-16【3Sum(三数和问题)】的更多相关文章

  1. C#LeetCode刷题之#16-最接近的三数之和(3Sum Closest)

    目录 问题 示例 分析 问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/3620 访问. 给定一个包括 n 个整数的 ...

  2. <LC刷题一>相加为0的数之leetcode1&2&15&16

    --题目导航见页面左上角的悬浮框#目录导航#-- 相似题型导航 1.1 twosum两数之和  ||  2.2 3Sum三数之和  ||  2.3 3Sum Closest最接近的三数之和 ----- ...

  3. leecode刷题(15)-- 验证回文字符串

    leecode刷题(15)-- 验证回文字符串 验证回文字符串 给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写. 说明:本题中,我们将空字符串定义为有效的回文串. 示例 ...

  4. 【LeetCode】15. 3Sum 三数之和

    作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 个人公众号:负雪明烛 本文关键词:3sum, 三数之和,题解,leetcode, 力扣,P ...

  5. [LeetCode] 15. 3Sum 三数之和

    Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find all un ...

  6. [leetcode]15. 3Sum三数之和

    Given an array nums of n integers, are there elements a, b, c in nums such that a + b + c = 0? Find ...

  7. [LeetCode] 3Sum 三数之和

    Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find all un ...

  8. LeetCode第十六题-找出数组中三数之和最接近目标值的答案

    3Sum Closest 问题简介: 给定n个整数的数组nums和整数目标,在nums中找到三个整数,使得总和最接近目标,返回三个整数的总和,可以假设每个输入都只有一个解决方案 举例: 给定数组:nu ...

  9. LeetCode(15):三数之和

    Medium! 题目描述: 给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组. 注意:答 ...

随机推荐

  1. 01背包----简单DP

    描述 且说上一周的故事里,小Hi和小Ho费劲心思终于拿到了茫茫多的奖券!而现在,终于到了小Ho领取奖励的时刻了! 小Ho现在手上有M张奖券,而奖品区有N件奖品,分别标号为1到N,其中第i件奖品需要ne ...

  2. poj1318 Word Amalgamation 字符串排序(qsort)

    Word Amalgamation Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 9794   Accepted: 4701 ...

  3. 【实战】Oracle注入总结

    小结: Union联合查询: order by 定字段 and 1=2 union select null,null..... from dual 然后一个一个去判断字段类型,方法如下 and 1=2 ...

  4. ibatis配置文件中的XML解析错误The content of elements must consist of well-formed character data or markup.

    在检查过所有的标签名都没有问题的情况下. xml中的小于号属于非法字符. SQL语句中则可能需要小于号,此时就需要用<![CDATA[  ]]>将小于号包裹,如此不会被xml解析器解析. ...

  5. spring利用cors处理跨域问题

    参考 http://blog.csdn.net/isea533/article/details/50449907 写的很全面 http://blog.csdn.net/a317560315/artic ...

  6. ionic 开发当中,有一些常用的方法。

    在开发项目的时候,有些常用的功能封装到一个类里. 以后要用的话,直接导入过来就可以用了,有一些方法是从网站复制过来的,有些方法是网上复制过来,然后自己修改了一下,标记一下吧!   /**      * ...

  7. (转)Saltstack系列

    Saltstack系列1:安装配置 Saltstack系列2:Saltstack远程执行命令 Saltstack系列3:Saltstack常用模块及API Saltstack系列4:Saltstack ...

  8. GitHub+Hexo+gulp搭建博客网站

    一.前期准备 1.注册GitHub账号. 不做说明 2.创建仓库 创建一个新的仓库来放置我们的文件. 3.下载安装Node.js https://nodejs.org/en/   两个版本,选择右边那 ...

  9. Beam概念学习系列之Pipeline 数据处理流水线

    不多说,直接上干货! Pipeline 数据处理流水线 Pipeline将Source PCollection ParDo.Sink组织在一起形成了一个完整的数据处理的过程. Beam概念学习系列之P ...

  10. 【Linux】修改ubuntu默认字符集

    今天把以前的项目移植到linux上了,我装的是ubuntu,web服务器是tomcat,发现用freemark模板生成的静态页面全 乱码了,在windows都是正常的,猜想可能是linux字符集的问题 ...