题目描述:
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例
1)输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
2)输入:nums = []
输出:[]
3)输入:nums = [0]
输出:[]
思路1:
暴力求解,三重循环,因为本题中要求不能够有重复的元组,而且本题同二数之和不同,不是返回index而是返回值。
为了避免重复,所以首先将数组进行排序,每次进行枚举的时候,要保证和上一次枚举的值不同,具体地:(伪代码)
nums.sort()
for first = 0 .. n-1
// 只有和上一次枚举的元素不相同,我们才会进行枚举
if first == 0 or nums[first] != nums[first-1] then
for second = first+1 .. n-1
if second == first+1 or nums[second] != nums[second-1] then
for third = second+1 .. n-1
if third == second+1 or nums[third] != nums[third-1] then
// 判断是否有 a+b+c==0
check(first, second, third)
时间复杂度O(n^3)。
思路2:
c = 0 - a - b,枚举a,b,然后用hash表查c。
class Solution(object):
def threeSum(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
if len(nums) < 3:
return []
nums.sort()
res= set() # 这里设置成一个set有帮助去重的功能,不能使用[]
for i, v in enumerate(nums[:-2]):
if i>= 1 and v == nums[i-1]: # 由于set的去重功效,这两行也可以没有
continue
d = {}
for x in nums[i+1:]:
if -v-x in d:
res.add((v, -v-x, x)) # 因为我们事先已经对num是进行了排序,所以得到的所有元素只要是满足条件的,元组都是一样的,采用add加入进入,重复的会自动去掉,而只采用[]是无法去重的
else:
d[x] = 1
return map(list, res)
时间复杂度为O(n^2)。
思路3:
a + b + c = 0
sort+find:首先对整个数组进行排序,然后a开始循环遍历,然后b 和 c 分别从剩下部分的两端(左边和右边)开始进行寻找是否a + b + c = 0, 这种方法又称为双指针,若>0.c端(也就是右侧向左移)<0,b端向右侧移动,直到左右两侧相遇。若遇到=0,则保存结果,还要注意保存之后为了避免有重复结果,要进行指针的处理。
class Solution(object):
def threeSum(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
result = []
s = sorted(nums) # 从小到大排序
for i in range(len(s)-2):
if i == 0 or s[i] != s[i-1]:
left = i + 1
right = len(s) - 1
while left < right:
if s[left] + s[right] > -s[i]:
right = right - 1
elif s[left] + s[right] == -s[i]:
result.append([s[i], s[left], s[right]])
while left+1 < len(s) and s[left] == s[left + 1]:
left = left + 1
while right - 1>= 0 and s[right] == s[right - 1]:
right = right - 1
left = left + 1
right = right - 1
else:
left = left + 1
return result
时间复杂度为O(n^2)。
相比较2的方法时间复杂度小但是用了一个哈希表,空间复杂度高,3的方法时间复杂度更大,但是空间复杂度为O(1)。
第三种方法是重要的!!!