Three sum解题心得

来源:互联网 发布:网络用语咸鱼什么意思 编辑:程序博客网 时间:2024/06/02 02:37

Three sum解题心得

来源:https://leetcode.com/problems/3sum/description/

  • Three sum解题心得
    • 题目重述
    • 解题过程
      • 版本一思路
        • 算法思想
        • 时间复杂度
        • 丑陋的代码
      • 版本二思路
        • 算法思想
        • 版本二代码

题目重述

在一串整数序列里找到这样三个和为零的数,找出该序列中所有这样的组合,以小到大的顺序排列,答案中要求不存在相同的组
例子:

For example, given array S = [-1, 0, 1, 2, -1, -4],

A solution set is:
[
[-1, 0, 1],
[-1, -1, 2]
]

解题过程

开始由于写过2Sum,就想过类比题目到3Sum中,只要遍历数组每个元素,设当前元素为S[i],设置其相反数为target,相当于2Sum问题中的两个数和的结果,由此可以将问题化解为多个2Sum子问题,同时时间复杂度可以达到O(n2),由于2Sum的最优复杂度为O(n)

但是。。。

当我匆匆打完过了测试样例,交上去后,讨厌的Wrong Answer出来了
最后发现这里需要将结果进行排序和消重,,,,于是就重新改进了自己的算法:

版本一思路

算法思想

  1. 对S使用sort排序(时间复杂度O(nlogn)
  2. 遍历S[i],在i+1到n(n为S长度)之间做2Sum问题,target=-S[i]
  3. 2Sum部分(为了顺序要求,与原先的2Sum有所不同,两次遍历效率降低)
    • 先用hash存取i+1到n的元素,按照{S[i],i}的形式存入hash
    • 再次由j从i+1到n遍历,通过之前的hash表快速查找S[j]互补的另一个数com,使S[j]+com=target
    • 每找到一组数则将结果插入输出数组
  4. 过程中可能遇到的bug (主要都是在消重排序上遇到的问题)

    • i,j遍历时需要跳过连续的元素,以防重复查询,所以这里的循环都用的是while,其中i是外层循环,j是内层循环做2Sum查找
    • 跳过重复元素的代码
        //外层循环    while(i+1<n&&sortedNums[i]==sortedNums[i+1])         i++;     i++;
        //内层循环    j++;    while(j<n&&j+1<n    &&sortedNums[j-1]==sortedNums[j]    &&sortedNums[j+1]==sortedNums[j])        j++;
    • 注意:在内层循环里的时候可以当前S[j]获得与S[j]互补的元素com,如果在S[j]之前则说明这个组合已经在结果中了,说明已经过了这个小序列的关于target的中心(因为序列有序,则x+y=target的一对组合是从序列两端向中间靠近的,有一对最近的x,y就当作target的临界值),后面遇到的组合都是不需要再去搜索了,可以跳出当前j的循环,结束2Sum
    • !!!push_back后还要把对应找到的S[j]互补的数com从hash表里删除,不然还是可能在关于targetd的中心处出现重复组合问题
    • hint:外层循环里加入判断,判断当前位置nums[i]如果大于0,则后面的搜索是找不到新的目标序列的(但是不知道为什么加入这个后反而变慢了)

时间复杂度

总而言之,其中hash的索引复杂度为O(1),索引两次循环遍历,就是O(n2)的时间复杂度

丑陋的代码

这里贴个代码
这里写图片描述

我的代码链接:https://github.com/zhanzongyuan/leetcode/blob/master/015_3Sum.cpp

最后,算法accpted!但是运行时间特别慢,只击败1%的cpp代码


版本二思路

经过我的一波研究,发现其实这里有个性质我忽略了
有序序列两端互补:就是排序后的在i+1到n的序列里的特性,即x+y=target的互补特性没有用到

算法思想

  1. 同样是类似与一中的思想,将问题转换为2Sum,但是要用到有序序列两端互补的特性
  2. 当j在i+1到n的第二层循环里使用两个下标,分别从两端向中间找互补和为target的一对元素
  3. 找到后就插入到结果里,再同时向中间移动下标,直到跳过多个重复元素,碰到新的元素
  4. 重复2-3直到下标相遇,当i结束则得到所有的满足条件的组,同时符合大学顺序
  5. 注意:这里需要对i进行一中类似的重复元素跳过的操作

版本二代码

这里写图片描述

我的代码链接:https://github.com/zongyuanZhan/leetcode/blob/master/015_3Sum.cpp

再一次accept,速度提高很多!超过75%的代码。

原创粉丝点击