Description:
Given an array nums of n integers, are there elements a, b, c in nums such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.
Note:
The solution set must not contain duplicate triplets.
Example:
Given array nums = [-1, 0, 1, 2, -1, -4],
A solution set is:
[
[-1, 0, 1],
[-1, -1, 2]
]
Analysis:
因为很久以前看过这道题的解法,所以首先想到了三指针,但是并不顺利。
一开始的方法是:(wrong)
l = 0
r = len(nums)-1
j = r-1
规则是:如果求和小于0,++left;如果大于零,--j 或者 --right且j=right-1,取决于j不能等于left;如果求和等于0,那么result.append(),并且--right且j=right-1。大循环满足条件是 left 存在的问题是,不能剔除重复,就算添加一行代码去重复,也还是会出现莫名其妙的漏掉结果,以及多结果。 全部从左往右,i,j,k = 0,1,2 初始化:left = 0,中间指针j = 1,right=last index Memory Usage: 16.6 MB, less than 90.14% of Python3 online submissions for 3Sum. source:https://github.com/MisterBooo/LeetCodeAnimation/blob/master/notes/LeetCode%E7%AC%AC15%E5%8F%B7%E9%97%AE%E9%A2%98%EF%BC%9A%E4%B8%89%E6%95%B0%E4%B9%8B%E5%92%8C.md Runtime: 88 ms, faster than 99.50% of C++ online submissions for 3Sum. Runtime: 820 ms, faster than 77.77% of Python3 online submissions for 3Sum.class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
if len(nums) < 3:
return []
nums.sort()
l = 0
r = len(nums)-1
j = r-1
result = []
while (l < r-1):
cache = nums[l]+nums[j]+nums[r]
if cache < 0:
l += 1
elif cache > 0 and j > l+1:
j -= 1
elif cache > 0 and j <= l+1:
r -= 1
j = r-1
else:
result.append([nums[l],nums[j],nums[r]])
r -= 1
j = r-1
return result
之后的方法:O(n^3),TLE
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
if len(nums) < 3:
return []
nums.sort()
result = []
i,j,k = 0,1,2
while (i <= len(nums)-3):
# print('\n',i,j,k)
cache = nums[i] + nums[j] + nums[k]
# print([nums[i],nums[j],nums[k]],cache)
if cache < 0:
k += 1
else:
if cache == 0 and [nums[i],nums[j],nums[k]] not in result:
result.append([nums[i],nums[j],nums[k]])
if k <= j+2:
i += 1
j = I+1
k = I+2
else:
j += 1
k = j+1
if k >= len(nums):
j += 1
k = j+1
if j >= len(nums) -1:
i += 1
j = I+1
k = I+2
return result
一个可行的解法:O(n^2)
每次大循环,left只要不超过len-3就行了,循环结尾++left。循环内部另一个循环是,中间指针j和right互相靠拢。
注意:每次移动任一指针,需要判断是否重复来加速,但引入的新麻烦是要注意index不要超出范围。class Solution:
def threeSum(self, nums):
if len(nums) < 3:
return []
nums.sort()
result = []
l,j,r = 0,1,len(nums)-1
while (l < r-1):
while (j < r):
cache_sum = nums[l]+nums[j]+nums[r]
cache_triplet = (nums[l],nums[j],nums[r])
if cache_sum < 0: # j太小
while(nums[j] == cache_triplet[1] and j < r):
j += 1
elif cache_sum > 0: # r太大
while(nums[r] == cache_triplet[2] and j < r):
r -= 1
else: # 正好合适
result.append(cache_triplet) # 已经在别的地方控制不会有重复了,可以放心append
if j >= r-2: # 没有下次机会了。如果中间数字存在重复或者不重复都不可能有新的结果。
break
while(nums[j] == cache_triplet[1] and j < r): # 只要j
Performance:
optimize the previous version: inspired by the following cpp solution
class Solution:
def threeSum(self, nums):
if len(nums) < 3:
return []
nums.sort()
result = []
l,j,r = 0,1,len(nums)-1
while (l < r-1):
if nums[l] > 0:
break
target = -nums[l]
while (j < r):
cache_sum = nums[j]+nums[r]
if cache_sum < target: # j太小
j += 1
elif cache_sum > target: # r太大
r -= 1
else: # 正好合适
result.append((nums[l],nums[j],nums[r])) # 已经在别的地方控制不会有重复了,可以放心append
while(j < r and nums[j] == nums[j+1]): # 只要j
Performance:
if cache_sum < target: # j太小
j += 1
elif cache_sum > target: # r太大
r -= 1
A great CPP solution:
class Solution {
public:
vector
Performance:
Memory Usage: 14.7 MB, less than 75.16% of C++ online submissions for 3Sum.Transform code form cpp to python:
class Solution:
def threeSum(self, nums):
if len(nums) < 3:
return []
nums.sort()
if nums[0] > 0 or nums[-1] < 0:
return []
result = []
for k in range(len(nums)):
if nums[k] >0:
break
if (k>0 and nums[k] == nums[k-1]):
continue
target = 0 - nums[k]
i = k+1
j = len(nums) -1
while(i < j):
if (nums[i]+nums[j] == target):
result.append([nums[k],nums[i],nums[j]])
while (i < j and nums[i] == nums[i+1]):
i += 1
while (i < j and nums[j] == nums[j-1]):
j -= 1
i += 1
j -= 1
elif nums[i]+nums[j] < target:
i += 1
else:
j -= 1
return result
Performance:
Memory Usage: 16.7 MB, less than 76.91% of Python3 online submissions for 3Sum.
Best implementation in Leetcode:
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
ans = []
numcounts = self.count(nums)
nums = sorted(numcounts)
for i, num in enumerate(nums):
if numcounts[num] >= 2:
if num == 0:
if numcounts[num] >= 3:
ans.append([0, 0, 0])
else:
if (-2 * num) in nums:
ans.append([num, num, -2*num])
if num < 0:
ans = self.twosum(ans, nums, numcounts, num, i)
return ans
def twosum(self, ans: List[List[int]], nums: List[int], numcounts, num: int, i: int):
twosum = -num
left = bisect.bisect_left(nums, (twosum-nums[-1]), i+1)
right = bisect.bisect_right(nums, (twosum//2), left)
for num2 in nums[left:right]:
num3 = twosum - num2
if num3 in numcounts and num3 != num2:
ans.append([num, num2, num3])
return ans
def count(self, nums: List[int]):
count = {}
for num in nums:
if num in count:
count[num] += 1
else:
count[num] = 1
return count
Performance: