【题目描述】

【一】 先说一种暴力思路,会发生超时。
首先想到的就是三层for循环的暴力方式,题干要求结果中的三元组不能重复,因此先排序后三层循环,三层循环的时候i之前的j不再遍历,j之前的k不再遍历,一直都是向后找的状态。
nums.sort()
length=len(nums)
res=[]
for i in range(length):
for j in range (i+1,length):
for k in range(j+1,length):
然后对三个元素求和,再判断一下res结果list中是否已经有了这个三元组,因为已经排序过了,此时判断的时候直接 if [nums[i],nums[j],nums[k]] in res就可以,如果和为0并且结果中不含,则加入到结果列表中。
sum=nums[i]+nums[k]+nums[j]
if sum==0 and not [nums[i],nums[j],nums[k]] in res:
res.append([nums[i],nums[j],nums[k]])
【暴力思路完整源代码】
class Solution(object):
def threeSum(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
nums.sort()
length=len(nums)
res=[]
for i in range(length):
for j in range (i+1,length):
for k in range(j+1,length):
sum=nums[i]+nums[k]+nums[j]
if sum==0 and not [nums[i],nums[j],nums[k]] in res:
res.append([nums[i],nums[j],nums[k]])
return res
【二】 优化后思路,类似一层循环,循环内实现二分查找,查找条件是 nums[left]+nums[right]==-nums[i]
优化思路就要抓住和为0这个点,排序过后,左指针指向i+1较小,右指针指向length-1较大,如果和大于0了,说明右指针的值太大,右指针需要左移;如果和小于0了,说明左指针的值太小,左指针需要右移;如果和为0,则保存起来,再左右指针同时移动,左指针右移,右指针左移,这样就比暴力遍历时间复杂度低。为了避免对重复数值的操作,有两次避免重复的操作,见下方代码备注处。 【优化源代码】
class Solution(object):
def threeSum(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
nums.sort()
res =[]
for i in range(len(nums)):
if i == 0 or nums[i]>nums[i-1]:
#如果nums[i]和上一次循环的nums[i]相等,则不执行此次循环,一次避免重复
l = i+1
r = len(nums)-1
while l < r:
s = nums[i] + nums[l] +nums[r]
if s ==0 :
res.append([nums[i],nums[l],nums[r]])
l +=1
r -=1
while r>l and nums[l]==nums[l-1]:
#如果左指针指向的元素与移动前相同,则继续右移直至不再相等,二次避免重复;右指针同理。
l+=1
while r>l and nums[r]==nums[r+1]:
r-=1
elif s>0:
r -=1
else :
l +=1
return res