给你一个整数数组 nums
,判断是否存在三元组 [nums[i], nums[j], nums[k]]
满足 i != j
、i != k
且 j != k
,同时还满足 nums[i] + nums[j] + nums[k] == 0
。请你返回所有和为 0
且不重复的三元组。
注意:答案中不可以包含重复的三元组。
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
解释:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0
。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0
。
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0
。
不同的三元组是 [-1,0,1]
和 [-1,-1,2]
。
注意,输出的顺序和三元组的顺序并不重要。
输入:nums = [0,1,1]
输出:[]
解释:唯一可能的三元组和不为 0
。
输入:nums = [0,0,0]
输出:[[0,0,0]]
解释:唯一可能的三元组和为 0
。
对于无序的输入数组,首先利用sort
函数进行排序,然后利用双指针法,固定一个数,然后利用双指针在剩下的数中寻找和为0的两个数。
即将问题转换为在数组中遍历i
,找到符合nums[j] + nums[k] = nums[i]
的j
和k
,由此将问题转换为两数之和问题。
for i in range(n - 2):
i
的范围为0
到n-3
,因为要保证i
后面至少有两个数,即j
和k
。
if self.nums[i] + self.nums[i + 1] + self.nums[i + 2] > 0:
break
if self.nums[i] + self.nums[n - 2] + self.nums[n - 1] < 0:
continue
- 在遍历
i
的过程中,分两种情况。如果i
及其最近的两个数i+1
和i+2
相加都>0
,那说明后续不可能有相加等于0的情况,可以直接跳出循环。 - 同理,如果
i
及其最后两个数n-2
和n-1
相加都<0
,那说明i
及其前面的数相加都<0
,可以跳过该i
,继续遍历下一个i
,因为随着nums[i]
的增大,还可能存在相加=0
的情况。
if i > 0 and self.nums[i] == self.nums[i - 1]:
continue
- 由于题目说不可以包含重复的三元组,那么就需要每个遍历的
i
值与前面的值不相等。 - 如果
i
与i-1
相等,则跳过该i
,因为i
与i-1
对应的结果已经计算过了,避免重复。
else:
ans.append([self.nums[i], self.nums[j], self.nums[k]])
j += 1
if j < k and self.nums[j] == self.nums[j - 1]:
j += 1
k -= 1
if j < k and self.nums[k] == self.nums[k + 1]:
k -= 1
- 如果
i
与j
和k
相加等于0,则将结果添加到ans
中,然后j
指针右移,k
指针左移,继续寻找下一个符合条件的j
和k
。 - 但是在
j
和k
移动的过程中,如同i
一样,也应注意避免重复。如果j
与j-1
相等,则跳过该j
,因为j
与j-1
对应的结果已经计算过了,避免重复。同理,如果k
与k+1
相等,则跳过该k
,因为k
与k+1
对应的结果已经计算过了,避免重复。
- 时间复杂度:
O(n^2)
,其中n
是数组nums
的长度。排序问题最小的时间复杂度是O(nlogn)
,枚举三元组的时间复杂度是O(n^2)
,因此总时间复杂度是O(n^2+nlogn)=O(n^2)
。 - 空间复杂度:
O(logn)
或者O(1)
,其中n
是数组nums
的长度。空间复杂度主要取决于排序的空间复杂度,也可忽略排序的复杂度。