leetcode M015
三数之和解法的本质就是暴力循环
方法一、纯暴力
原始的暴力循环N^3时间复杂度,代码如下:
很显然超时了
def threeSum(self, nums: List[int]) -> List[List[int]]:
n = len(nums)
ans = []
if n<3:
return []
for i in range(n-2):
for j in range(i+1, n-1):
for k in range(j+1, n):
if nums[i]+nums[j]+nums[k]==0:
temp = [nums[i],nums[j], nums[k]]
temp.sort()
if temp not in ans:
ans.append(temp)
return ans
方法二、暴力优化
剩下的核心在于怎么把不需要的重复的循环遍历去除掉,官方的解法就是先把原来的数组排个序,再从头遍历,去除重复的方式是双指针,一个从头走一个从尾走,指针碰到一样的直接跳到下一个,代码如下:
def threeSum(self, nums: List[int]) -> List[List[int]]:
n = len(nums)
if n<3:
return []
ans = []
nums.sort()
for i in range(n):
if nums[i]>0:
return ans
# 注意i==0的时候不能跳
# 这一步是最难理解的,为什么i也可以跳
# 这是因为i如果重复的情况上一个循环已经出现过了
if i!=0 and nums[i]==nums[i-1]:
continue
l = i+1
r = n-1
while l<r:
if nums[i]+nums[l]+nums[r]==0:
ans.append([nums[i],nums[l],nums[r]])
while l<r and nums[l]==nums[l+1]:
l += 1
while l<r and nums[r] == nums[r-1]:
r -= 1
l += 1
r -= 1
elif nums[i]+nums[l]+nums[r]<0:
l += 1
else:
r -= 1
return ans
上面说的为什么i也可以跳,因为如果出现 -1 -1 2 这样的情况,我怕如果i指向第一个-1,下一次i会直接蹦到2,不经过第二个-1可能会漏掉某些答案,事实上这是不可能的,因为第一个循环时l指针会走过第二个-1
不要总是再脑子里面瞎几把想一些根本不存在的情况!
什么情况下会用到双指针:
当我们需要枚举数组中的两个元素,如果我们发现随着第一个元素的递增,第二个元素是递减的,那么就可以使用双指针的方法