LeetCode 三数之和

三数之和

参考资料: LeetCode评论

题目描述

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

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

例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4],

满足要求的三元组集合为:
[
  [-1, 0, 1],
  [-1, -1, 2]
]

解题方法

方法一:

思路:
双重循环,将三数之和转化为求两数之和问题;
对nums排序,每次循环进行一次去重
结果:
显而易见,超时了…

    def threeSum(self, nums):
        result = []
        nums.sort()
        print(nums)          
        for i in range(0, len(nums)):
            if i==0 or nums[i]!=nums[i-1]:
                for j in range(i+1, len(nums)):
                    if j==i+1 or nums[j]!=nums[j-1]:
                        if 0-nums[i]-nums[j] in nums[(j+1):]:
                            result.append([nums[i], nums[j],0-nums[i]-nums[j]])
        return result   

在这里插入图片描述

方法二:

思路:
接着上面的思路
根据题目特点,将三数之和的情况分位三种:[0, 0, 0] , [pos,0,neg] , [pos, pos, neg]or[neg, pos, pos]
但是实际上算法复杂度应该是没有变的
结果:
显而易见, 还是超时了…!!!!

class Solution:
    def threeSum(self, nums):
        if (not nums) or len(nums)<3 : return []
        pos_num = [num for num in nums if num>0]
        neg_num = [num for num in nums if num<0]
        zero_num = [num for num in nums if num==0]
        neg_num.sort()
        pos_num.sort()
        result=[]
        if len(zero_num)>0:
            for i in range(0, len(pos_num)):
                if pos_num[i] not in pos_num[:i]:
                    if (0-pos_num[i]) in neg_num:
                        result.append([0, pos_num[i], (0-pos_num[i])])
        if len(zero_num)>=3:
            result.append([0, 0, 0])
        for i in range(0, len(pos_num)-1):
            if pos_num[i] not in pos_num[:i]: 
                for j in range(i+1, len(pos_num)): 
                    if pos_num[j] not in pos_num[i+1:j]: 
                        num3 = 0 - pos_num[i] - pos_num[j]
                        if num3 in neg_num:
                            result.append([pos_num[i], pos_num[j], num3]) 
        for i in range(0, len(neg_num)):  
            if neg_num[i] not in neg_num[:i]:
                for j in range(i+1, len(neg_num)):
                    if neg_num[j] not in neg_num[i+1:j]:
                        num3 = 0 - neg_num[i] - neg_num[j]
                        if num3 in pos_num:                        
                            result.append([neg_num[i], neg_num[j], num3])
        return result
        

在这里插入图片描述

方法三:

思路:
接上面的思路
重新考虑去重问题,直接使用不重复且排序的nums, 在最后一层循环中考虑重复问题
结果:
终于不超时了, 但是执行时间和内存消耗都不佳…

class Solution:
    def threeSum(self, nums):
        result = []
        nums_dict = {}
        for num in nums:
            nums_dict[num] = nums_dict.get(num, 0)+1
        print(nums_dict)
        if (0 in nums_dict) and nums_dict[0]>=3:
            result.append([0, 0, 0])
            
        nums = sorted(list(nums_dict.keys()))
        for i, num1 in enumerate(nums):
            for num2 in nums[i+1:]:
                if nums_dict[num1]>=2 and num1*2+num2==0:
                    result.append([num1, num1, num2])
                if nums_dict[num2]>=2 and num2*2+num1==0:
                    result.append([num1, num2, num2])
                num3 = 0-num1-num2
                if num3>num2 and num3 in nums_dict:
                    result.append([num1, num2, num3])
        return result   

在这里插入图片描述

方法四:

同样将问题转化为求两数之和问题,但是不用双重循环, 而是用两端逼近的方法:
在一重循环下,即确定数组中第一个数的情况下, 对剩下的数通过排序后,通过比较前后两端数以及num0之和 与 0 的差异,
确定逼近的节奏。
同样通过两次去重。

class Solution:
    def threeSum(self, nums):
        result = []
        nums.sort()
        print(nums)
        if len(nums)<3: return []
        for i, num0 in enumerate(nums):
            if i>0 and num0==nums[i-1]: continue   #去重
            left_index = i+1
            right_index = len(nums)-1
            while left_index<right_index:
                sum3 = nums[left_index]+nums[right_index]+num0
                #print([num0, nums[left_index], nums[right_index]], sum3)
                if sum3==0:
                    result.append([num0, nums[left_index], nums[right_index]])
                    while(left_index<len(nums)-1 and nums[left_index] == nums[left_index+1]): left_index+=1  # 去重
                    while(right_index>1 and nums[right_index] == nums[right_index-1]): right_index-=1       # 去重
                    left_index+=1
                    right_index-=1                      
                elif sum3<0:
                    left_index+=1                
                else :
                    right_index-=1             
        return result  

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值