- 题目描述
给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
- 示例
例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为:
[
[-1, 0, 1],
[-1, -1, 2]
]
- 解决思路
(1)最开始我的解决思路是使用暴力,从头开始遍历所有的元素,寻找满足条件的三元组并输出,编码之后发现输出的结果有问题,主要体现在元素没有排序,而且还会有重复的三元组出现。想到的解决方案是把数组变为set,然后再排序,之后再进行暴力的遍历,但是结果仍然不能通过,讨论区有很多回答说的是超时问题,我的答案却是索引的问题,这么看来按暴力解法的话,我的思路其实也不是那么完全正确,使用python,网友的解决方案如下:
(2)仍旧是先进行排序,排序之后进行遍历,在遍历的过程中,分别考虑三元组的三个元素,这三个元素都有可能遇到重复的数值,我们通过比较i,j,k分别对应的元素与相邻元素的值是否相同,控制i,j,k是否需要向后(i,j)或向前(k)移动。除此之外,通过判断当前三数之和与0的关系,可以决定j,k哪一个需要向前或向后移动。
(3)要特别注意对i的判断和控制,第二天复习时自己敲,发现了这个问题,对博客进行了修改。
- 代码
class Solution(object):
def threeSum(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
if(len(nums)) < 3:
return []
#对数组排序
nums.sort()
#要返回的集合
sets = []
#遍历数组
for i in range(len(nums)-2):
#不可以用这种方式来进行判断
# if (nums[i] == nums[i+1]):
# continue
#原因在于i前边的元素肯定是参与过运算的,如果i和前一个相同,那么就没有必要再进行一次对j和k的遍历(第二个数和第三个数)
#而i后边的元素是没有作为三元组的第一个数存在过的,如果判断i和i+1的大小的话,会忽略掉j = i+1的情况
#其实是对第一个数字的控制,判断当前i对应的数字是否作为第一个数参与过遍历计算。如果判断i与i+1,则达不到这样的作用
if(i>0 and nums[i] == nums[i-1]):
continue
#j是前边的指针
j = i +1
#k是后边的指针
k = len(nums) - 1
while(j<k):
rr = nums[i]+nums[j]+nums[k]
#如果三数之和等于0
if(rr==0):
sets.append([nums[i],nums[j],nums[k]])
#考虑前边的指针遍历到相同的数值
while(j<k and nums[j] == nums[j+1]):
j += 1
#考虑后边的指针遍历到相同的数值
while(j<k and nums[k] == nums[k-1]):
k -= 1
j += 1
k -= 1
#如果三数之和小于0,那么前边的指针向后移动(j指示的元素数值变大)
elif(rr<0):
j += 1
#如果三数之和大于0,那么后边的指针向前移动(k指示的元素数值变小)
else:
k -= 1
return sets