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

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

示例:

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

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

解法一:排序+双指针

排序的目的是为了在自左向右遍历nums[first], nums[second], nums[third],能够方便的跳过重复元素。当nums[first]确定时,nums[second]与nums[third]可以通过双指针向两边相向移动的方式来找到target = -nums[first]。注意由于这题与两数之和那题不一样,会存在多组解,不唯一,因此second需要遍历全部first+1 ~ n - 1,third从n-1位置向左移动。

  1. class Solution:
  2. def threeSum(self, nums: List[int]) -> List[List[int]]:
  3. n = len(nums)
  4. nums.sort()
  5. ans = list()
  6. # 枚举 a
  7. for first in range(n):
  8. # 需要和上一次枚举的数不相同
  9. if first > 0 and nums[first] == nums[first - 1]:
  10. continue
  11. # c 对应的指针初始指向数组的最右端
  12. third = n - 1
  13. target = -nums[first]
  14. # 枚举 b
  15. for second in range(first + 1, n):
  16. # 需要和上一次枚举的数不相同
  17. if second > first + 1 and nums[second] == nums[second - 1]:
  18. continue
  19. # 需要保证 b 的指针在 c 的指针的左侧
  20. while second < third and nums[second] + nums[third] > target:
  21. third -= 1
  22. # 如果指针重合,随着 b 后续的增加
  23. # 就不会有满足 a+b+c=0 并且 b<c 的 c 了,可以退出循环
  24. if second == third:
  25. break
  26. if nums[second] + nums[third] == target:
  27. ans.append([nums[first], nums[second], nums[third]])
  28. return ans

另一种书写方式。其中从11行开始与TwoSum一样,是两端双指针。区别在于TwoSum在遇到target后直接就退出了,二ThreeSum中需要继续向后移动j。也正因为解不唯一,因此移动j和k都需要用while来跳过移动方向上的重复元素。

  1. class Solution:
  2. def threeSum(self, nums: List[int]) -> List[List[int]]:
  3. n = len(nums)
  4. nums.sort()
  5. ans = []
  6. for i in range(n):
  7. if i > 0 and nums[i] == nums[i - 1]:
  8. continue
  9. j, k, target = i + 1, n - 1, -nums[i]
  10. while j < k:
  11. if nums[j] + nums[k] == target:
  12. ans.append([nums[i], nums[j], nums[k]])
  13. # 跳过重复nums[j]后尝试下一个
  14. while j < k and nums[j + 1] == nums[j]:
  15. j += 1
  16. j += 1
  17. elif nums[j] + nums[k] > target:
  18. # 跳过重复nums[j]后尝试下一个
  19. while j < k and nums[k - 1] == nums[k]:
  20. k -= 1
  21. k -= 1
  22. else:
  23. # 跳过重复nums[k]后尝试下一个
  24. while j < k and nums[j + 1] == nums[j]:
  25. j += 1
  26. j += 1
  27. return ans