题目链接
方法 1:双指针
思路
- 遍历数组中的数固定为
i
,在剩余未遍历的数中利用相向双指针 left
和 right
寻找 j
和 k
。 - 每个指针都去重,则可保证答案中无重复数组。
- 利用极值进行剪枝优化。
- 注意不可以使用“固定 j,在两侧寻找
left
和 right
的方法,理由如下:

以下为以 j 为固定数的错误示例代码,可以自己拿去 leetcode 试验一下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
| class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
nums.sort() # 先对数组排序
ans = []
n = len(nums)
for j in range(1, n - 1): # 固定中间的数 nums[j]
l, r = j - 1, j + 1 # 左指针在 j 左侧,右指针在 j 右侧
while l >= 0 and r < n:
s = nums[l] + nums[j] + nums[r]
if s == 0:
ans.append([nums[l], nums[j], nums[r]])
# 找到一个解后,跳过重复的 l 和 r
while l > 0 and nums[l] == nums[l - 1]:
l -= 1
while r < n - 1 and nums[r] == nums[r + 1]:
r += 1
l -= 1
r += 1
elif s < 0:
r += 1 # 和小了,右侧指针向右移动
else:
l -= 1 # 和大了,左侧指针向左移动
return ans
|
代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
| class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
nums.sort() # 先对数组排序
ans = []
n = len(nums)
for i in range(n - 2):
x = nums[i]
if i > 0 and x == nums[i - 1]:
continue
if x + nums[i+1] + nums[i+2] > 0:
break
if x + nums[-1] + nums[-2] < 0:
continue
j = i + 1
k = n - 1
while j < k:
s = x + nums[j] + nums[k]
if s > 0:
k -= 1
elif s < 0:
j += 1
else:
ans.append([x, nums[j], nums[k]])
# 从下一个数开始去重
j += 1
# 最终需停在不重复的下一个数
while j < k and nums[j] == nums[j-1]:
j += 1
k -= 1
while k > j and nums[k] == nums[k+1]:
k -= 1
return ans
|
复杂度
- 时间复杂度:$O(n ^ 2)$
- 空间复杂度:$O(1)$,不记入排序的栈使用。