1. 题目
给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为:
[
[-1, 0, 1],
[-1, -1, 2]
]
2. 思路
这道题最直接想到的应该是两数之和,两数之和还是比较基础的,采用通知记录的方式,维护一个字典,看新的数是否属于这个字典的键即可。三数之和也可以使用类似的办法,但是题目要求的是不能有重复的,这就比较难办了,那可能只有先将其排序,然后判断一下他们是否在集合中,思路就显而意见了,代码如下:
def threeSum(self, nums: List[int]) -> List[List[int]]: result = [] for i,j in enumerate(nums): temp = nums[:i]+nums[i+1:] dic1 = {} dic2 = {} for count,k in enumerate(temp): if k not in dic1: dic1[-j-k] = k else: dic2[tuple(sorted([j,k,-j-k]))] = [j,k,-j-k] return dic2.values()
3. 改进
然而不幸的是,这个复杂度太高,跑不过所有case便会超时,在这之前我使用的是判断list是否在list中,这样的话更没有办法通过所有的case,复杂度太高,优化以后使用字典但还是在全是0的case失败了。
经过修改后和一些边界条件,给出一个通过了case,但是极其慢的解法,我称其为无情解法:
def threeSum(self, nums: List[int]) -> List[List[int]]: dic2 = {} if (len(set(nums) ) == 1)and (len(nums) > 2): #主要是去除全是0 的情况,全是0 就会导致最后的循环复杂度过高 if 0 in set(nums): return [[0,0,0]] for i,j in enumerate(nums): temp = nums[:i]+nums[i+1:] dic1 = {} for count,k in enumerate(temp): if k not in dic1: dic1[-j-k] = k else: dic2[tuple(sorted([j,k,-j-k]))] = [j,k,-j-k] return dic2.values()
下面给出正确的解法,使用双指针
class Solution: def threeSum(self, nums: List[int]) -> List[List[int]]: nums = sorted(nums) res = [] dic1 = {} for i,j in enumerate(nums): if j > 0: continue temp = nums[i+1:] left = 0 right = len(temp)-1 while(left < right): if j + temp[left]+temp[right] == 0: dic1[(j,temp[left],temp[right])] = [j,temp[left],temp[right]] # res.append([j,temp[left],temp[right]]) right -= 1 elif j + temp[left]+temp[right] > 0: right -= 1 else: left += 1 return dic1.values()