LintCode 57. 三数之和

题目描述

给出一个有n个整数的数组S,在S中找到三个整数a, b, c,找到所有使得a + b + c = 0的三元组。

在三元组(a, b, c),要求a <= b <= c,结果不能包含重复的三元组。


测试样例

输入:[2,7,11,15]

输出:[]

输入:[-1,0,1,2,-1,-4]

输出:[[-1, 0, 1],[-1, -1, 2]]


思路

将三数之和转换为两数之和求解,两数之和的目标为第三个数的相反数。对数组进行排序,然后依次取出一个数作为固定数,接着在除这个数之外的子序列中拿出头尾两个数,将它们之和与目标比较,若一致则说明找到解,否则缩减子序列的范围继续查找。


具体步骤

1、由于要求最终生成的每个三元组是升序的,因此可以先将数组由小到大进行排序;

2、若排序后数组的第一个元素都大于0,说明不可能存在三数之和为0的情况;

3、否则,遍历数组中的每个数,直到倒数第3个数,将其作为a,当a不是序列中第一个数的时候,要先判断下a是否和位于它前一位的数相同,若是,则进行下一轮循环;

4、将位于a之后的所有数中取出首尾两个数分别作为b和c;

5、将b+c与0-a进行比较,若前者大,则将c前面的一个数(比c小)作为c;若后者大,则将b后面的一个数(比b大)作为b;若两者相等,则找到一个符合要求的三元组(a, b, c),记录下来;

6、在4中若找到解,由于符合要求的三元组不能重复,因此需要将b向前移动1位和将c向后移动一位。另外,若b和c没有走到重合的位置,且b和它前一位的数相同,则b继续往前走;若c和它后一位的数相同,c也继续往后走;

7、重复5、6直至b和c走到重合的位置;

8、重复3-7直至数组中倒数第3个数也处理完


代码

class Solution:

    """

    @param numbers: Give an array numbers of n integer

    @return: Find all unique triplets in the array which gives the sum of zero.

    """

    def threeSum(self, numbers):

        # write your code here

        if not numbers:

            return []


        # 先进行排序

        seq = sorted(numbers)

        # 若序列中的最小数大于0,

        # 则不可能有三数之和为0的情况

        if seq[0] > 0:

            return []


        ans = []


        for i in range(len(seq) - 2):

            # 去重

            if i > 0 and seq[i] == seq[i - 1]:

                continue


            a = seq[i]

            target = 0 - a

            j, k = i + 1, len(seq) - 1


            while j < k:

                '''去重'''

                if j - i > 1 and seq[j] == seq[j - 1]:

                    j += 1

                    continue


                b, c = seq[j], seq[k]


                if b + c > target:

                    k -= 1

                elif b + c < target:

                    j += 1

                else:

                    ans.append([a, b, c])

                    '''由于结果不能包含重复的三元组,因此b和c的位置需要移动'''

                    j += 1

                    k -= 1


                    '''去重'''

                    while j < k and seq[j] == seq[j - 1]:

                        j += 1


                    while j < k and seq[k] == seq[k + 1]:

                        k -= 1


        return ans




附:方法2 —— 不需排序,代码量较少但空间复杂度更高


思路

实质也是将三数之和转化为两数之和。
不同的是,直接遍历序列中的每个数,直到倒数第3个数,将其作为a,然后遍历a之后的每个数,作为b,看看 c = 0 - a - b 是否在之前的遍历过程中遇到过,若是则说明找到一组解;否则将b记录下来,这样,遍历到后面的b时,此时的b就有可能成为后续的c = 0 - a - b。


代码

from collections import defaultdict

class Solution:

    """

    @param numbers: Give an array numbers of n integer

    @return: Find all unique triplets in the array which gives the sum of zero.

    """

    def threeSum(self, numbers):

        # write your code here

        if not numbers:

            return []


        ans = []


        for i in range(len(numbers) - 2):

            a = numbers[i]

            # b + c = 0 - a

            target = 0 - a

            residual = defaultdict(bool)


            for j in range(i + 1, len(numbers)):

                b = numbers[j]

                c = target - b


                # 把此时的c当作以前的b,

                # 看是否出现过

                if residual.get(c):

                    seq = sorted([a, b, c])


                    # 不能包含重复的三元组

                    if seq not in ans:

                        ans.append(seq)

                else:

                    # 由于结果不能包含重复的三元组,

                    # 因此是有当没有找到满足条件的方案时

                    # 才把此时的b记录下来

                    residual[b] = True


        return ans

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,634评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,951评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,427评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,770评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,835评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,799评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,768评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,544评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,979评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,271评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,427评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,121评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,756评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,375评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,579评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,410评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,315评论 2 352