问题:给定一个包含 n 个整数的数组 nums
,判断 nums
中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
Example:
Given array nums = [-1, 0, 1, 2, -1, -4],
A solution set is:
[
[-1, 0, 1],
[-1, -1, 2]
]
方法一:有序数列首尾逼近查找
我们先来考虑两个数的情况。其它条件不变,假设查找两个元素a,b,使得a + b = 0。暴力方法是先确定一个数,然后在剩下的数中查找满足条件的数,这种算法是两重循环,时间复杂度为O(n²)。但如果我们的数组是有序的,即数组内数字从小到大排列,我们分别设置首尾两个指针 i,j。这样 i初始时指向组内最小数字, j初始时指向组内最大数字。通过比较 nums[i]+nums[j]和0的大小关系来对下标进行移动。如果比0小,那么需要将 i 向右移动,以增加总和。反之亦然。
那么对于三个数的情况,因为数组是一维的,只能设置首尾两个指针,因此需要先确定一个数,然后对剩下的两个数用上述逼近的方法进行查找。
同时要注意的是,题中所给数组中存在重复元素,而答案要求不包含重复的三元组。因此在进行查找时,应跳过重复数字。
这里对倒数第2行代码及其上方的两个while做一下说明:假设有一组数字[1,2,2,2,2,3,4,5,6,6,6,6,7],假设现在 j 指向最左端的2, k 指向最右端的6,那么经过两个while循环后,j 将指向最右端的2,k 将指向最左端的6,[1,2,2,2,2,3,4,5,6,6,6,6,7]。为了避免重复结果,j 和 k 仍然分别要继续移动一位,即倒数第二行代码。
#Python
class Solution(object):
def threeSum(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
nums.sort() #先对数组进行排序
res = []
for i in range(len(nums)-2): #先确定第一个数,因为总共要有3个数,所以只能循环至倒数第三个数
if i > 0 and nums[i] == nums[i-1]: #如果后面的数和前面的相同,为避免重复答案,跳过这次循环
continue
j = i + 1;k = len(nums) - 1 #对剩下的两个数设置首尾指针
while j < k:
s = nums[i] + nums[j] + nums[k]
if s < 0:
j = j + 1 #当前和比0小,需要增加当前的和,j右移
elif s > 0:
k = k - 1 #当前和比0大,需要减小当前的和,k左移
else:
res.append((nums[i],nums[j],nums[k])) #找到满足条件的数
while j < k and nums[j] == nums[j+1]: #左边移动到相同连续数字的最右端
j = j + 1
while j < k and nums[k] == nums[k-1]: #右边移动到相同连续数字的最左端
k = k - 1
j = j + 1;k = k -1 #上面的操作结束后,两个指针所指的值只是位于相同值的末端,值本身没有变化本身,需要继续移动到不同数字上
return res