前言:剑指offer刷题系列
问题:
输入一个递增排序的数组和一个数字s,在数组中查找两个数,使得它们的和正好是s。如果有多对数字的和等于s,则输出任意一对即可。
示例:
输入:nums = [2,7,11,15], target = 9
输出:[2,7] 或者 [7,2]
思路:
就是简单的两层for循环,逐一判断列表中的元素是否存在两个元素和等于target目标值。
时间复杂度是O(n*n)
基于上述思考,代码如下:
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
for i in range(len(nums)):
j = i + 1
for j in range(len(nums)):
if nums[i] + nums[j] == target:
return [nums[i],nums[j]]
执行结果如下图:
一个巨大的测试用例让我的算法逻辑超出了时间限制。于是我做了一些改变,尝试一个循环从前开始,一个循环从后开始,还是超出了时间限制。
所以换了一种思路:
思路:
我想到了target-num[i]就是我的目标函数,只要在列表中找到这个值就行,一个循环就可以搞定。
我想到了列表有一个查找函数find()和cout()函数,两个函数都试了一下,都不行。虽然这个方法表面只有一个for循环,但是实际上这两个函数本身实现也是一个循环,时间复杂度并没有改变。
基于上述思考,代码如下:
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
for i in range(len(nums)):
if nums.count(target-nums[i]) > 0:
return [nums[i],target-nums[i]]
执行结果如下图:
还是被这个测试用例挡住了,我犯了难,难道有一次循环的方法可以搞定?
然后我去看了评论区,猛然想起这是双指针里面的题目,肯定要用双指针的方法呀
思路:
两个指针从数组两端分别移动,由于序列是递增的,nums[i]+nums[j] 与 target总共有三种情况,分别是:
nums[i]+nums[j] == target 匹配成功,立即返回[nums[i],nums[j]]
nums[i]+nums[j] < target 匹配失败,总数小了,前面的小数往后移 i+1
nums[i]+nums[j] > target 匹配失败,总数大量,后面的大数往前移,j-1
基于上述思考,代码如下:
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
i = 0
j = len(nums) - 1
while i < j:
if nums[i] + nums[j] == target:
return [nums[i],nums[j]]
if nums[i] + nums[j] > target:
j -= 1
if nums[i] + nums[j] < target:
i +=1
执行结果如下图:
学到的知识点:
又一次加深对双指针的学习应用