167. 两数之和 II - 输入有序数组

难度:中等 | 主题:数组 + 双指针

题目

给你一个下标从 1 开始的整数数组 numbers,该数组已按非递减顺序排列。请你找出两个数满足相加之和等于目标数 target。返回这两个数的下标。你可以假设每个输入只对应唯一的答案。

示例

输入:numbers = [2,7,11,15], target = 9

输出:[1,2]

解释:下标从 1 开始,numbers[1]+numbers[2]=9


思路

先讲个故事:两个人在数轴上找朋友

你和朋友站在一根有序的数轴上,想找一个位置组合能让你们俩的坐标加起来等于 100。

朋友站在最左边(最小数),你站在最右边(最大数)。

  • 如果和太大 → 你往左走(减小)

  • 如果和太小 → 朋友往右走(增大)

你们相向而行,总能在某个点碰头。


引导式推导:从无序到有序

第 1 题(两数之和) 用哈希表是因为数组无序,不得不存下所有数的位置。

本题 数组已排序——有序就是信息,双指针利用这个信息把空间降到 O(1)。


graph LR

    A["[2, 7, 11, 15] target=9<br/>↓&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;↓<br/>l=0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;r=3"] --> B{"2+15=17 > 9"}

    B -->|r左移| C["[2, 7, 11, 15]<br/>↓&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;↓<br/>l=0&nbsp;&nbsp;&nbsp;r=2"]

    C --> D{"2+11=13 > 9"}

    D -->|r左移| E["[2, 7, 11, 15]<br/>↓&nbsp;&nbsp;&nbsp;↓<br/>l=0&nbsp;r=1"]

    E --> F{"2+7=9 ✓"}

为什么一定能找到? 单调性保证搜索空间不断缩小——l 右移和增大,r 左移和减小。每次比较排除一个元素,类似于在二维有序矩阵中搜索。

场景解法空间理由
有序数组双指针O(1)利用有序性缩小搜索范围
无序数组哈希表O(n)需要记录已遍历元素的位置

代码

 
def twoSum(self, numbers, target):
 
    left, right = 0, len(numbers) - 1   # 双指针指向数组两端
 
    while left < right:                 # 不能等号,一个数不能跟自己相加
 
        total = numbers[left] + numbers[right]
 
        if total == target:             # 找到目标,题目保证唯一解
 
            return [left + 1, right + 1]  # 下标从 1 开始
 
        elif total < target:            # 和太小 → 左指针右移
 
            left += 1
 
        else:                           # 和太大 → 右指针左移
 
            right -= 1
 
    return []                           # 理论上不会执行(题目保证有解)
 

复杂度

指标解释
时间O(n)每个元素最多访问一次
空间O(1)就两个指针
哈希表法O(n) 空间无序数组才用

实战考量

频率分析

出现在:一面基础题,常和 01两数之和 对比出题。约 35% 的会用这道题考察”场景选择能力”——有序用双指针,无序用哈希。

延伸思考

Q:为什么有序数组不用哈希表?

A:哈希表 O(n) 空间,双指针 O(1) 空间。有序数组的双指针信息来自排序本身,哈希表既浪费空间又没利用有序这个已知条件。

Q:如果数组可能有重复元素,答案不唯一呢?

A:双指针找到一个后,左右都跳过重复值继续搜索,类似 15三数之和 的去重逻辑。

Q:如果要求返回所有不重复的组合?

A:找到一对后,left 和 right 各自跳过重复值再继续。核心是 while left < right and nums[left] == nums[left-1]: left += 1

Q:while 条件为什么是 < 不是 <=

A:一个数不能和自己相加形成两个数。l == r 时指向同一个元素,不合法。

Q:下标为什么要 +1?

A:题目要求下标从 1 开始(1-indexed),而代码里用的是 0-indexed。

易错点

  • 下标从 1 开始返回,忘记 left + 1right + 1

  • while left < right 写成 while left <= right

  • 答案唯一 → 直接 return,不需要继续搜索


生活类比

找两数之和 → 相向双指针

就像两个人在一个递增的山坡上从两头往中间走,一个从山脚往上,一个从山顶往下。

和太小说明山脚的人走快点,和太大说明山顶的人走慢点。

双指针就是——每次只走一步,但一步缩小一行可能性。


相关题目

题目关系
01两数之和同族无序版,用哈希表
15三数之和三数版,固定一个后内部就是本题
125验证回文串双指针相向遍历,经典场景

→ 返回题单:LeetCode学习路线图 > 一、数组与哈希(含双指针、矩阵)

速记卡(面试闪卡)

Q1:一句话讲清「167. 两数之和 II - 输入有序数组」到底是什么?

A:有序数组找两数之和,用相向双指针把空间压到 O(1)。

Q2:一、题目与有序性带来的红利 —— 怎么理解?

A:像在排好队的数列里找搭档:题目保证有序且唯一解,这正是信息——利用有序性就不用哈希表存位置了。英文:Two Sum II / Sorted Input。

Q3:二、思路:两数轴上相向而行 —— 怎么理解?

A:像两人在递增山坡从两头往中间走:和太小左边前进、和太大右边后退,每次只走一步就排除一个元素,必能碰头。英文:Two Pointers。

Q4:三、为什么不用哈希表 —— 怎么理解?

A:像已有排序还去建索引纯属浪费:哈希表要 O(n) 空间存位置,双指针靠”有序”这个已知条件直接 O(1),既省空间又用了题目给的信息。英文:O(1) Space。

Q5:四、边界与易错点 —— 怎么理解?

A:像过门槛的细活:下标从 1 开始记得 +1,循环用 < 不用 <= (一个数不能配自己),找到唯一解直接 return 别多搜。英文:1-indexed / Edge Cases。

Q6:核心速记主线有哪些?

  • 核心招式:左右指针相向,和大小决定谁移动

  • 空间优势:有序 → 双指针 O(1),无序才用哈希 O(n)

  • 复杂度:时间 O(n)、空间 O(1)

  • 易错:下标+1、while 用 <、唯一解即返回

口诀

A:有序两数指两头,

相向双针步步收;

和大小定谁走,

O(1) 空间稳拿下。

相关链接