15. 3Sum_左右开工,遍历找出符合目标的数字
题目:
Given an array S of n integers, are there elements a, b, c in S 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.
For example, given array S = [-1, 0, 1, 2, -1, -4], A solution set is: [ [-1, 0, 1], [-1, -1, 2] ]
代码:
题目意思很简单:从数组中挑出三个数字,相加和为0,返回所有满足条件的结果:
第一反应,当然是遍历3次,吭哧吭哧写完了:
def threeSum(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
nums.sort()
result = []
for x in range(0,len(nums)-2):
for i in range(x+1,len(nums)-1):
#print(i,nums[i],result)
#if self.judge(nums[i],result):continue
for j in range(i+1,len(nums)):
#if self.judge(nums[j],result):continue
if(nums[x]+nums[i]+nums[j]==0):
if [nums[x],nums[i],nums[j]] not in result:
result.append([nums[x],nums[i],nums[j]])
return result
但是,问题来了,LeetCode提交测试会超时,测试数据是一串126个元素的数组,并且有120组符合条件的答案。
这种遍历的方法试了一下,大概需要0.36s,确实不快,必定时间复杂度有O(n^3)了
想啊想,试了很多种,都不行,只能百度了一下大神算法,一时,只用了0.003秒,而且准确的说,除去枚举第一个数之外,其余只需要遍历一遍:
总共的时间复杂度不到:O(n^2)
拷贝过来记录,并共大家参考学习:
def threeSum2(self, nums):
'''
题意:求数列中三个数之和为0的三元组有多少个,需去重
暴力枚举三个数复杂度为O(N^3)
先考虑2Sum的做法,假设升序数列a,对于一组解ai,aj, 另一组解ak,al
必然满足 i<k j>l 或 i>k j<l, 因此我们可以用两个指针,初始时指向数列两端
指向数之和大于目标值时,右指针向左移使得总和减小,反之左指针向右移
由此可以用O(N)的复杂度解决2Sum问题,3Sum则枚举第一个数O(N^2)
使用有序数列的好处是,在枚举和移动指针时值相等的数可以跳过,省去去重部分
'''
nums.sort()
res = []
length = len(nums)
for i in range(0, length - 2):
if i and nums[i] == nums[i - 1]:
continue
target = nums[i] * -1
left, right = i + 1, length - 1
while left < right:
if nums[left] + nums[right] == target:
res.append([nums[i], nums[left], nums[right]])
right -= 1
left += 1
while left < right and nums[left] == nums[left - 1]:
left += 1
while left < right and nums[right] == nums[right + 1]:
right -= 1
elif nums[left] + nums[right] > target:
right -= 1
else:
left += 1
return res