题目描述:
给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例:
给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为:
[
[-1, 0, 1],
[-1, -1, 2]
]
题目原链接:https://leetcode-cn.com/problems/3sum/
本题采用的是排序 + 双指针的方法,思路如下:
- 先将给定
nums
排序,复杂度为O(NlogN)
。 - 固定 33 个指针中最左(最小)数字的指针 k,双指针 i,j 分设在数组索引
(k, len(nums))
两端,通过双指针交替向中间移动,记录对于每个固定指针 k 的所有满足nums[k] + nums[i] + nums[j] = 0
的 i,j 组合:
1. 当nums[k] > 0
时直接break跳出:因为nums[j] >= nums[i] >= nums[k] > 0
,即 3 个数字都大于 0 ,在此固定指针 k 之后不可能再找到结果了。
2. 当k > 0
且nums[k] 等于 nums[k - 1]
时即跳过此元素nums[k]
:因为已经将nums[k - 1]
的所有组合加入到结果中,本次双指针搜索只会得到重复组合
3. i,j 分设在数组索引(k, len(nums))
两端,当i < j时循环计算s = nums[k] + nums[i] + nums[j]
,并按照以下规则执行双指针移动:
当s < 0
时,i += 1
并跳过所有重复的nums[i]
;
当s > 0
时,j -= 1
并跳过所有重复的nums[j]
;
当s == 0
时,记录组合[k, i, j]
至res,执行i += 1
和j -= 1
并跳过所有重复的nums[i]
和nums[j]
,防止记录到重复组合。
Python code:
def threesum(nums):
if len(nums) < 3:
return []
if len(nums) == 3 and sum(nums) != 0:
return []
k, res = 0, []
nums.sort()
for k in range(len(nums)):
if nums[k] > 0:
break
if k > 0 and nums[k] == nums[k-1]:
continue
low, high = k+1, len(nums) - 1
while low < high:
if nums[k] + nums[low] + nums[high] ==0:
res.append([nums[k], nums[low], nums[high]])
low += 1
high -=1
# 遇到重复元素跳过
while low < high and nums[low] == nums[low - 1]: low += 1
while low < high and nums[high] == nums[high + 1]: high -= 1
elif nums[k] + nums[low] + nums[high] < 0:
low += 1
# 遇到重复元素跳过
while low < high and nums[low] == nums[low-1]: low +=1
elif nums[k] + nums[low] + nums[high] > 0:
high -= 1
# 遇到重复元素跳过
while low < high and nums[high] ==nums[high +1]:high -=1
return res
threesum([-1, 0, 1, 2, -1, -4])
Out: [[-1, -1, 2], [-1, 0, 1]]
参考:https://leetcode-cn.com/problems/3sum/solution/3sumpai-xu-shuang-zhi-zhen-yi-dong-by-jyd/