题目
给你一个整数数组 nums ,判断是否存在三元组
[
n
u
m
s
[
i
]
,
n
u
m
s
[
j
]
,
n
u
m
s
[
k
]
]
[nums[i], nums[j], nums[k]]
[nums[i],nums[j],nums[k]] 满足
i
!
=
j
、
i
!
=
k
i != j、i != k
i!=j、i!=k 且
j
!
=
k
j != k
j!=k ,同时还满足
n
u
m
s
[
i
]
+
n
u
m
s
[
j
]
+
n
u
m
s
[
k
]
=
=
0
nums[i] + nums[j] + nums[k] == 0
nums[i]+nums[j]+nums[k]==0 。请你返回所有和为
0
0
0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
例子
- 输入:
n
u
m
s
=
[
−
1
,
0
,
1
,
2
,
−
1
,
−
4
]
nums = [-1,0,1,2,-1,-4]
nums=[−1,0,1,2,−1,−4]
输出: [ [ − 1 , − 1 , 2 ] , [ − 1 , 0 , 1 ] ] [[-1,-1,2],[-1,0,1]] [[−1,−1,2],[−1,0,1]]
解释:
n u m s [ 0 ] + n u m s [ 1 ] + n u m s [ 2 ] = ( − 1 ) + 0 + 1 = 0 。 nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0。 nums[0]+nums[1]+nums[2]=(−1)+0+1=0。
n u m s [ 1 ] + n u m s [ 2 ] + n u m s [ 4 ] = 0 + 1 + ( − 1 ) = 0 。 nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0。 nums[1]+nums[2]+nums[4]=0+1+(−1)=0。
n u m s [ 0 ] + n u m s [ 3 ] + n u m s [ 4 ] = ( − 1 ) + 2 + ( − 1 ) = 0 。 nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0。 nums[0]+nums[3]+nums[4]=(−1)+2+(−1)=0。
不同的三元组是 [ − 1 , 0 , 1 ] 和 [ − 1 , − 1 , 2 ] [-1,0,1] 和 [-1,-1,2] [−1,0,1]和[−1,−1,2] 。
注意,输出的顺序和三元组的顺序并不重要。 - 输入:
n
u
m
s
=
[
0
,
1
,
1
]
nums = [0,1,1]
nums=[0,1,1]
输出: [ ] [] []
解释:唯一可能的三元组和不为 0 0 0 。 - 输入:
n
u
m
s
=
[
0
,
0
,
0
]
nums = [0,0,0]
nums=[0,0,0]
输出: [ [ 0 , 0 , 0 ] ] [[0,0,0]] [[0,0,0]]
解释:唯一可能的三元组和为 0 0 0 。
思路
1. 暴力解法
虽然说暴力解法超时了,但大家会的思路基本上就是这个了,并且大部分人可能只会三重 f o r for for循环,但是并不知道之后怎么去进行去重。这里记录三种方法。
- 时间复杂度: O ( n 3 ) O(n^3) O(n3)
- 空间复杂度: O ( n ) O(n) O(n)
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
if not nums:
return []
result = []
n = len(nums)
for i in range(n-2):
for j in range(i+1, n-1):
for k in range(j+1, n):
if nums[i] + nums[j] + nums[k] == 0:
# 判断三元组中的元素是否相等,避免重复
# 这种方法又暴力写法又复杂不建议使用
if [nums[i], nums[j], nums[k]] not in result and [nums[i], nums[k], nums[j]] not in result \
and [nums[j], nums[i], nums[k]] not in result and [nums[j], nums[k], nums[i]] not in result \
and [nums[k], nums[i], nums[j]] not in result and [nums[k], nums[j], nums[i]] not in result:
result.append([nums[i], nums[j], nums[k]])
return result
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
if not nums:
return []
result = []
n = len(nums)
for i in range(n-2):
for j in range(i+1, n-1):
for k in range(j+1, n):
if nums[i] + nums[j] + nums[k] == 0:
# 对三元组的元素进行排序实现去重
triplet = sorted([nums[i], nums[j], nums[k]])
if triplet not in result:
result.append(triplet)
return result
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
n = len(nums)
res = []
# 要先对数组排序,排序之后通过比较可以避免找出相同的数字
nums.sort()
for i in range(n-2):
if i > 0 and nums[i] == nums[i-1]: # 避免重复计算
continue
for j in range(i+1, n-1):
if j > i + 1 and nums[j] == nums[j-1]: # 避免重复计算
continue
for k in range(j+1, n):
if k > j + 1 and nums[k] == nums[k-1]: # 避免重复计算
continue
total = nums[i] + nums[j] + nums[k]
if total == 0:
res.append([nums[i], nums[j], nums[k]])
return res
2. 双指针➕排序
这种方法类似于上述最后一种去重方法,只不过上述的方法要三重for循环,会超出时间限制。以下这种方法利用双指针实现两次for循环,减少时间复杂度。
class Solution:
def threeSum(self, nums):
n = len(nums)
nums.sort()
ans = list()
# 枚举 a
for first in range(n):
# 需要和上一次枚举的数不相同
if first > 0 and nums[first] == nums[first - 1]:
continue
# c 对应的指针初始指向数组的最右端
third = n - 1
target = -nums[first]
# 枚举 b
for second in range(first + 1, n):
# 需要和上一次枚举的数不相同
if second > first + 1 and nums[second] == nums[second - 1]:
continue
# 需要保证 b 的指针在 c 的指针的左侧
# 如果俩数之和大于target,说明数字大了,右指针third就要往左移,寻找小的数字
# 反之,second就要往右移,寻找大的数字
while second < third and nums[second] + nums[third] > target:
third -= 1
# 如果指针重合,随着 b 后续的增加
# 就不会有满足 a+b+c=0 并且 b<c 的 c 了,可以退出循环
if second == third:
break
if nums[second] + nums[third] == target:
ans.append([nums[first], nums[second], nums[third]])
return ans