这道题记得之前做过,但是想不起来了。。总结一下:
函数的主要步骤和关键点:
- 排序:对输入的整数数组
nums
进行排序。这是非常重要的,因为它允许我们使用双指针技巧来高效地找到满足条件的三元组。 - 初始化:定义
ans
列表来存储所有找到的三元组,并初始化三个指针first
、second
和third
。 - 枚举第一个数:使用
first
指针遍历整个数组。为了避免重复的三元组(例如[-1, 0, 1]
和[0, -1, 1]
),我们需要跳过所有与前一个数相同的数。 - 设置目标和双指针:将目标和
target
设置为-nums[first]
,然后初始化third
指针为数组的最后一个元素的索引。此时,我们需要找到两个数(nums[second]
和nums[third]
),它们的和等于target
。 - 枚举第二个数:使用
second
指针从first + 1
开始遍历数组。同样地,为了避免重复的三元组,我们需要跳过所有与前一个数相同的数。 - 双指针技巧:当
nums[second] + nums[third] > target
时,说明third
指向的数太大了,我们需要将third
向左移动;否则,我们检查是否找到了一个满足条件的三元组。 - 避免重复:当
second
和third
相遇或nums[second] + nums[third] == target
时,我们需要检查是否找到了一个有效的三元组,并将其添加到ans
列表中。然后,我们继续移动second
指针,但在这之前,我们需要跳过所有与当前nums[second]
相同的数,以避免找到重复的三元组。 - 返回结果:返回存储了所有满足条件的三元组的
ans
列表。
改进点:这个算法的时间复杂度是O(n^2),其中n是数组nums
的长度。
-
设 s = nums[first] + nums[first+1] + nums[first+2],如果 s > 0,由于数组已经排序,后面无论怎么选,选出的三个数的和不会比 s 还小,所以只要 s > 0 就可以直接 break 外层循环了。
-
如果 nums[first] + nums[n-2] + nums[n-1] < 0,由于数组已经排序,nums[first] 加上后面任意两个数都是小于 0 的,所以下面的双指针就不需要跑了。但是后面可能有更大的 nums[first],所以还需要继续枚举,continue 外层循环。
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:
j += 1
elif s > 0:
k -= 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