首先暴力解法不用说了,看了评论的双指针提示,尝试写了如下代码:
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
nums.sort()
result=[]
for i in range(len(nums)):
l=i+1
r=len(nums)-1
while(l<r):
if(nums[i]+nums[l]+nums[r]<0 ):
l=l+1
elif(nums[i]+nums[l]+nums[r]>0 ):
r=r-1
elif((nums[i]+nums[l]+nums[r]==0 )):
result.append([nums[i],nums[l],nums[r]])
break
return result
问题大的很,首先是边界判断,l!=r 和l<r 有点纠结,前者貌似也行,但是有点不符合左右指针的特点。第二break语句有点模糊,这里的break加入之后,万一在等于0之后,右边还有其他满足的情况呢?[-2,0,1,1,2]比如 第一遍遍历到-2 0 2时就结束了,但其实-2 1 1也满足没有找到所有情况。改进之后
在以上基础之上改进,然后超时了,淦!!!:
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
nums.sort()
result=[]
for i in range(len(nums)):
l=i+1
r=len(nums)-1
while(l<r):
if(nums[i]+nums[l]+nums[r]<0 ):
l=l+1
elif(nums[i]+nums[l]+nums[r]>0 ):
r=r-1
elif((nums[i]+nums[l]+nums[r]==0 )):
result.append([nums[i],nums[l],nums[r]])
l=l+1
final=[]
for i in result:
if i not in final:
final.append(i)
return final
直接上大佬代码吧:
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
#
#-4 -1 -1 0 1 2
# i l r
nums.sort()
res=[]
i=0
for i in range(len(nums) - 2):#减2是因为左右指针占了两个位置
if nums[i] > 0: break # 1. because of j > i > k.
if i > 0 and nums[i] == nums[i - 1]: continue # 2. skip the same `nums[k]`.
l, r = i + 1, len(nums) - 1
while l != r: # 3. double pointer
s = nums[i] + nums[l] + nums[r]
if s < 0:
l += 1
while l != r and nums[l] == nums[l - 1]: #跳过重复的值nums[l] != nums的时候指针就不走了
l += 1
elif s > 0:
r -= 1
while l != r and nums[r] == nums[r + 1]:
r -= 1
else:
res.append([nums[i], nums[l], nums[r]])
l += 1
r -= 1
while l != r and nums[l] == nums[l - 1]:
l += 1
while l != r and nums[l] == nums[r + 1]:
r -= 1
return res
N数之和通用思路
解题思路
首先要熟悉求两数之和的写法,然后在 N > 2时,采用递归处理,一次减少1。
关键点是:
- 先对nums排序;
- 递归处理时的剪枝处理(参考注释)
这种写法参考了国际站上的文章,我觉得是最好的一种解法了。
代码
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
if not nums: return []
# 先排序,关键!
nums.sort()
ans = set()
N, target = 3, 0
self._find_sum(nums, 0, N, target, [], ans)
return list(ans)
def _find_sum(self, nums, start, N, target, path, ans):
# terminator
if len(nums) < N or N < 2: return
# process
if N == 2:
# 两数求和
d = set()
for j in range(start, len(nums)):
if target - nums[j] in d:
ans.add(tuple(path + [target - nums[j], nums[j]]))
else:
d.add(nums[j])
else:
for i in range(start, len(nums)):
# 剪枝1: target比剩余数字能组成的最小值还要小 或 比能组成的最大值还要大,就可以停止循环了
if target < nums[i] * N or target > nums[-1] * N: break
# 剪枝2: 去重
if i > start and nums[i] == nums[i - 1]: continue
# drill down
self._find_sum(nums, i + 1, N - 1, target - nums[i], path + [nums[i]], ans)
return