跟着 - b站up主刷题
这里面有个知识点: 相向双指针 。
1️⃣ 暴力解法
两遍循环,遍历第一个元素,接着从第二个元素开始找,判断两数之和是否和target相等,如果相等,直接返回。
时间复杂度 O(n^2)。 这样没有用到里面的一个性质,整个数组是有序的。
2️⃣ 相向指针解法
从题意中,可以知道,整个数组是非递减顺序排列 的,我们用最两头的元素相加和target比较,
- 如果nums[0] + nums[n-1] (两数相加) 比 target 大,那么 nums[1] ... nums[n-2] 中的任何一个数和 nums[n-1] 相加 都比target大,就需要把nums[n-1] 丢弃掉,用 nums[n-2] 元素和 nums[0]相加与target比较。
- 同理可得,如果nums[0] + nums[n-1] 比 target 小,那么 nums[1] ... nums[n-2] 中的任何一个数和 nums[n-1] 相加 都比target小,就需要把nums[0] 丢弃掉,用 nums[1] 元素和 nums[i-1]相加与target比较。
代码: 时间复杂度 O(n)
class Solution(object):
def twoSum(self, numbers, target):
"""
:type numbers: List[int]
:type target: int
:rtype: List[int]
"""
left = 0
right = len(numbers) - 1
while left < right:
s = numbers[left] + numbers[right]
if s == target:
break
if s < target:
left +=1
else:
right -=1
return [left+1, right+1]
这题可以说是两数之和的升级版。
1️⃣ 暴力解法
这题当然也可以用暴力法解决,那么时间复杂度就是O(n^3) ,三遍循环即可。
2️⃣ 相向双指针解法。
通过上一题可以知道,如果数组有序的话,我们就可以使用双向双指针,可以把O(n^2) 时间复杂度降低到O(n), 那么只要我们从第一个元素开始遍历,那么另外两个元素 可以转化为相加为0的问题。
题意中有几个要求:
- 三元组的顺序不重要。
- i < j < k
- 答案中不包含重复元素。
只需要我们把数组排序,从第一个元素开始遍历,剩下的两个元素,就可以使用双向双指针即可。
答案中不包含重复元素:
[-4,-1,-1,0,1,2] 比如 nums[1] + num[3] + nums[4] = 0 , nums[2] + num[3] + nums[4] = 0
那么如何过滤掉这种情况呢, 就是下一次进入的时候,发现当前的num[i] 和上一个nums[i-1] 相等,就过滤掉。注意要过滤掉i=0 的情况,也就是说,nums[-1] 的情况。 为什么要用continue,是因为 for循环,自动+1。
if i > 0 and nums[i-1] == x:
continue
对于j 和 k 的情况,同样的道理。 当找到了一组满足条件的解时,j 到 k 要遍历一遍,此时j已经+1了, 就如果nums[j] == nums[j-1] ,继续j+=1, 跳过这个k。
同样的对于k来说, k已经-1, k 到j 开始遍历,如果 num[k] = nums[k+1] , 继续让k-=1 , 跳过这个k。
这题还有两个小优化:
- 如果 x + nums[i+1] +num[i+2] > 0 , 那么直接 break吧, 从大到小排序的,后面的已经不可能再有=0的解了。
- 如果 x + nums[-1] + nums[-2] < 0, 直接continue 吧, 就需要从下一个x,这个x 已经不可能找到=0的解了。
class Solution(object):
def threeSum(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
nums.sort() # [-1,0,1,2,-1,-4] => [-4,-1,-1,0,1,2]
ans = []
print(nums)
n = len(nums)
for i in range(n-2):
x = nums[i]
if x + nums[i+1] + nums[i+2] >0:
break
if x + nums[-1] + nums[-2] <0:
continue
if i > 0 and nums[i-1] == x:
continue
j = i + 1
k = n - 1
while j < k :
s = x + nums[j] + nums[k]
if s < 0:
j +=1
elif s > 0:
k -=1
else:
ans.append([x, nums[j], nums[k]])
j += 1
while j < k and nums[j] == nums[j-1]:
j +=1
k -= 1
while k > j and nums[k] == nums[k+1]:
k -=1
return ans
s = Solution()
a = [-1,0,0,1,2,-1,-4]
print(s.threeSum(a))