剑指 Offer 57. 和为s的两个数字

44 阅读2分钟

前言:剑指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]]

执行结果如下图:

image-20230801145415777.png

一个巨大的测试用例让我的算法逻辑超出了时间限制。于是我做了一些改变,尝试一个循环从前开始,一个循环从后开始,还是超出了时间限制。

所以换了一种思路:

思路:

我想到了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]]

执行结果如下图:

image-20230801145415777.png

还是被这个测试用例挡住了,我犯了难,难道有一次循环的方法可以搞定?

然后我去看了评论区,猛然想起这是双指针里面的题目,肯定要用双指针的方法呀

思路:

两个指针从数组两端分别移动,由于序列是递增的,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

执行结果如下图:

image-20230801152739120.png

学到的知识点:

又一次加深对双指针的学习应用