三数之和

三数之和

题目描述:

给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 abc ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。

注意:答案中不可以包含重复的三元组。

示例 1

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

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

示例 2

输入:nums = []

输出:[]

示例 3

输入:nums = [0]

输出:[]

思路分析

    三数之和来自于两数之和的扩展,但两数之和那个题,题目保证只有一种结果,找到则返回即可。而三数之和要找到所有的结果,所以是无法直接复用两数之和的代码的。并且这个题要求是不可以包含重复三元组,如何才能不重复地获得数据呢,我采用的方式是排序+遍历+双指针。

    这一题我认为我的代码是算又臭又长的了,所以一定要先看思路,看懂之后自己写无非也就那样,就不会被看起来很麻烦的代码劝退了:

    首先对数组进行排序,当然只要涉及到排序操作,时间复杂度最低也是nlogn了。可以自己写个快排,也可以直接使用sort(因为这里排序并不是重点,偷个懒也并不太影响)。

   对数组进行排序之后,我们从头开始遍历整个排序数组,把当前遍历到的值作为第一个数,并对当前位置往后的数组范围做两数之和的处理。这样一来,数组中的每一个数(除了倒数两个)都被当作过第一个数来对待,可以充分考虑到所有情况,并且因为只考虑这个数位置往后的数组,也不会造成重复的现象。

对于处理两数之和问题,因为已经说明了无法复用之前的代码,所以要采取另一种方式:也就是在盛最多水的容器题目中用到的双指针。具体思路直接看代码吧,其实也还是从两边向中间靠拢的过程而已。

代码:

class Solution(object):

    def threeSum(self, nums):

        def two_sum(nums,target):#先定义两数之和的函数

#用双指针,否则超时

            i = 0#i代表左指针

            lenth = len(nums)#总长度

            j = lenth-1#j代表右指针

            res = []#存放结果,因为我们要找到所有结果,所以要把结果都存起来

            while i<j:#当左右指针未相遇时

                summ = nums[i]+nums[j]

                if summ==target:

#假设二者之和等于目标值,以列表的形式添加进res

                    res.append([nums[i],nums[j]])

                    #找到目标之后 ,还要继续缩进

                    #左

                    now_i = nums[i] #暂存一下当前的值

#左指针向右移动,这里因为可能会有重复的值,所以要一直移动到与当前值不同的位置

                    while i<j and nums[i]==now_i:

                        i+=1

                    #右

#右指针向左移动,也是一样,移到下一个不同的位置处

                    now_j = nums[j] #暂存一下当前的值

                    while i<j and nums[j]==now_j:

                        j-=1 

                #若sum比target小,则只需要移动左指针就好了,因为左指针向右移动,可以让和慢慢变大。这就是排序的作用。

                elif summ<target:

                    now_i = nums[i]

                    while i<j and nums[i]==now_i:

                        i+=1

                #若sum比target大,则只需移动右指针即可,原因同理。

                elif summ>target:

                    now_j = nums[j]

                    while i<j and nums[j]==now_j:

                        j-=1 

            return res#最终,res里就是一对对和为target的列表。

        left = 0#回到外面,我们定义left为0,开始遍历整个数组

        lenth=len(nums)

        total_res=[]#存放总结果

        nums.sort()#使用sort进行排序,这个是必须操作。

    #所以后面传入two_sum的函数,也是排序过的有序数组。

        while left<lenth-2:#left一直遍历到倒数第二个

#(因为至少要留两个给twoSum函数)

            rs = two_sum(nums[left+1:],-nums[left])#以-nums[left]作为target

            if rs:#如果返回的rs有值,其实就是一个个列表

                for r in rs:

#遍历每一个列表,加上当前的nums[left]就组成了其中一个结果

                    r.append(nums[left])

                    total_res.append(r)

            now_left=nums[left]#暂存一下当前的值

#更新移动left,也是移动到下一个值不同的位置为止

            while left<lenth-2 and nums[left]==now_left:

                left+=1

        return total_res

这样子,就可以既全面,又不会重复且不会超时地找到所有三元组了。

posted @   JunanP  阅读(10)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示