
👉 题目禁止的是:
下标重复(同一个元素不能用两次)
结果三元组重复(值完全相同的三元组不能出现两次)
👉 题目并不禁止:
值相同但来自不同位置的元素
由三维降到二维, 针对任意索引i的nums[i] 求[i+1,size )范围内不重复的twoSum target = - nums[i];
- 排序数组,方便去重。
- 固定一个元素 nums[i],用双指针扫描剩余部分的数组来寻找另外两个数。
时间复杂度:O(n²)
排序是 O(n log n)。
双指针扫描是 O(n)。对于每个 i,双指针的扫描是 O(n) 的操作,而外层循环遍历了 n 个元素。
总的时间复杂度为 O(n²) +O(n log n) = O(max(n log n, n²)) = O(n²)
没有使用额外的存储结构(例如哈希表、栈等),而是仅使用了常数级的空间(如变量 i, left, right, res)。因此,空间复杂度是 O(1)
python
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
if len(nums) < 3:
return []
nums.sort() # 从小到大排序
res =[]
for i in range(len(nums)):
if nums[i] >0: # 已排序,第一个就>0,后面不会有匹配的, 退出当前循环
break # 不能 return [], 因为之前的循环res可能已经有值,只能break或return res
if i>0 and nums[i] == nums[i-1]: # 当前nums[i]与nums[i-1]相同,前面已经处理过,跳过
continue
# 由三维降到二维,开始左右指针: 针对任意索引i的nums[i] 求[i+1,size )范围内不重复的twoSum target = - nums[i];
# twoSum 开始
left = i+1
right = len(nums)-1
while left < right:
target = 0-nums[i]
# 正好找到
if nums[left] + nums[right] == target:
res.append([nums[i], nums[left], nums[right]])
while(left < right and nums[left]==nums[left+1]): # 跳过重复元素
left +=1
while(left < right and nums[right]==nums[right-1]): # 跳过重复元素
right -= 1
# 正常移动双指针
left += 1
right -= 1
# 没找到
elif nums[left] + nums[right] > target: # 已排序,说明要再小一点
right -= 1 # 右指针左移
else: #nums[left] + nums[right] < target: # 已排序,说明要再大一点
left +=1
return res
在发现一个三元组时,为什么不是直接跳过首尾:left += 1;right -= 1,而是要判断
nums[left] == nums[left + 1]:
nums[right] == nums[right - 1]
避免重复三元组:因为数组是排过序的,可能会遇到值相同的元素。为了避免返回重复的三元组,需要跳过相同的元素。
假设数组已经排序:[-1, -1, 0, 1, 1]
我们找到的三元组是 [-1, 0, 1]。那么:
左指针 left 现在指向 0。
右指针 right 现在指向 1。
如果我们直接移动指针,左指针 left 会指向下一个 0,右指针 right 会指向下一个 1,这时候我们会重复添加 [-1, 0, 1] 这个三元组。为了避免这种情况,要跳过这些相同的元素