167 两数之和 II - 输入有序数组
题目
给定一个已按照 升序排列 的整数数组 numbers ,请你从数组中找出两个数满足相加之和等于目标数 target 。
函数应该以长度为 2 的整数数组的形式返回这两个数的下标值。numbers 的下标 从 1 开始计数 ,所以答案数组应当满足 1 <= answer[0] < answer[1] <= numbers.length 。
你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素。
示例 1:
输入:numbers = [2,7,11,15], target = 9
输出:[1,2]
解释:2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。 示例 2:
输入:numbers = [2,3,4], target = 6
输出:[1,3] 示例 3:
输入:numbers = [-1,0], target = -1
输出:[1,2]
提示:
2 <= numbers.length <= 3 * 104
-1000 <= numbers[i] <= 1000
numbers 按 递增顺序 排列
-1000 <= target <= 1000
仅存在一个有效答案
思路 I —— 哈希表
相比于本题的姊妹篇 两数之和 I,本题的输入是有序数组,应该是更容易 AC。
- 由题意可知,给定输入中,有且仅有一个有效答案。那么就可以用哈希表来实现。
- 步骤:
- 将数组元素存到哈希表中:
{元素 : 元素在数组中的位置}
(ps:此处的位置 = 索引 + 1
) - 遍历数组,如果当前元素
numbers[i]
和target - numbers[i]
都在哈希表中,那么得到该有效答案。
- 将数组元素存到哈希表中:
代码 I
class Solution:
def twoSum(self, numbers: List[int], target: int) -> List[int]:
# 此处的 位置 = 索引 + 1
dic = {item:idx+1 for idx, item in enumerate(numbers)}
for i in range(len(numbers)):
if target - numbers[i] in dic:
return [i+1, dic[target - numbers[i]]]
思路 II —— 双指针
- 初始化一对一头一尾的双指针:
left, right
- 指针移动的条件:(大前提:存在有效答案,并且,输入的数组是有序的)
- 如果左右指针所指的元素「和为
target
」,那么返回左右指针所在的位置。 - 如果左右指针所指的元素之和大于
target
,那么说明指针之和太大,应该减少一些,又因为数组已排好序,只能将右指针向左移动,以此减小「左右指针之和」。 - 同理,如果左右指针所指的元素之和小于
target
,那么需要将左指针向右移动,整体增加「左右指针之和」逐渐向target
靠拢。
- 如果左右指针所指的元素「和为
代码 II
class Solution:
def twoSum(self, numbers: List[int], target: int) -> List[int]:
left, right = 0, len(numbers)-1
while left < right:
if numbers[left] + numbers[right] == target:
return [left+1, right+1]
elif numbers[left] + numbers[right] > target:
right -= 1
else:
left += 1
分析
两种方法都:
- 时间复杂度需要
O(n)
来遍历数组。 - 空间复杂度需要
O(n)
来保存元素。
留下评论