https://leetcode.cn/problems/3sum/
给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请你返回所有和为 0 且不重复的三元组。注意:答案中不可以包含重复的三元组。
示例 1:
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
示例 2:
输入:nums = [0,1,1]
输出:[]
解释:唯一可能的三元组和不为 0 。
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
# 时间复杂度:O(n^2)
# 空间复杂度:O(1)
# 难度:☆☆☆
# 数组有序,相向双指针
# 和167题对照看,167题是两数之和等于target,本题可以看成nums[j] + nums[k] = -nums[i],也是一种两数之和等于target
# 本题不是求索引,而是求数字,那么可以先排序,然后用相向双指针
# 要求不包含重复三元组,像示例1一样,遍历了-1后组成[-1,0,1]符合结果,但是-1有2个,第2个-1必须忽略
# 抽象成语句就是,当前值nums[i]和前一个值nums[i - 1]如果相同,忽略本次循环
nums.sort()
ret = []
n = len(nums)
for i in range(n - 2): # 因为是i < j < k,三个数,所以遍历时i最多遍历到倒数第3个数
if i >= 1 and nums[i] == nums[i - 1]:
continue
# 升序数组,最小的三个数和都大于0了,后面就不用遍历了
if nums[i] + nums[i + 1] + nums[i + 2] > 0:
break
# nums[i]和数组中最大的2个数相加小于0,忽略本次循环,注意不能break,因为num[i]后面会变大,还会有机会等于0
if nums[i] + nums[-2] + nums[-1] < 0:
continue
# 以下代码就是167题的相向双指针思路
left, right = i + 1, n - 1
while left < right:
sums = nums[i] + nums[left] + nums[right]
if sums > 0:
right -= 1
elif sums < 0:
left += 1
else:
ret.append([nums[i], nums[left], nums[right]])
# 除了需要以nums[i]为标的的去重,以nums[left]和以nums[right]为标的的去重也要做
left += 1
while left < right and nums[left] == nums[left - 1]:
left += 1
right -= 1
while left < right and nums[right] == nums[right + 1]:
right -= 1
return ret