图解题库 / 对撞双指针

167. 两数之和 II

中等 含交互动画

学完这道你应该能: 说清它为什么用「对撞双指针」,而不是死记步骤; 合上页面,自己默写出核心代码; 用 30 秒把思路讲清楚。

题目描述

一个升序数组里找两个数,使它们相加等于 target,返回它们的下标(从 1 开始)。

numbers = [2, 7, 11, 15]
target = 9
输出 = [1, 2] (2 + 7 = 9)

思路解析

直接套两数之和的哈希表也能做,O(n) 时间 O(n) 空间。但题目特意给了「有序」——不用就亏了。有序数组有个更省空间的招:对撞双指针。

l 指头、r 指尾。两数之和太大说明要换个小的,r 左移;太小说明要换个大的,l 右移;正好相等就找到了。有序保证了「移哪边、和往哪变」是确定的。

l=0, r=3:首尾相加 2 + 15 = 17,比 9 大。说明 15 太大,r 左移一格。

l=0, r=2:2 + 11 = 13,仍然大于 9,r 再左移一格。

l=0, r=1 · 命中:2 + 7 = 9,正好等于 target!返回它们的下标(从 1 数):[1, 2],结束。

和太大时,l 配最大的 r 都超了,那 l 配中间任何数更超——所以 l 这个数可以「连同它和 r 的组合」一起排除,r 安全左移。这保证了双指针不会跳过正确解。

只要数组有序、要找「一对满足某和/差」,就首尾双指针:一次比较砍掉一头,O(n) 搞定。

参考代码(Python)

Python
1l, r = 0, len(numbers) - 1
2while l < r:
3    s = numbers[l] + numbers[r]
4    if s == target: return [l + 1, r + 1]   # 下标从1开始
5    elif s > target: r -= 1                 # 太大,缩右
6    else: l += 1                            # 太小,进左

复杂度分析

  • 时间复杂度:O(n) —— l、r 共走一遍
  • 空间复杂度:O(1) —— 只用两个指针

套路模板

记住骨架:首尾出发、命中即返、偏大缩右、偏小进左。三数之和、盛水容器、平方数之和都是它的变体。

Python
1# 有序数组找一对满足条件的元素都套
2l, r = 0, n - 1
3while l < r:
4    if 满足(l, r): return ...        # 命中
5    elif 偏大: r -= 1               # 缩右变小
6    else: l += 1                    # 进左变大

易错点

  • 在无序数组上用双指针 → ✅ 先确认数组有序(双指针的正确性依赖单调性)
  • 返回 [l, r] → ✅ 本题要求下标从 1 开始 [l+1, r+1](看清题目下标基准)

以上文字与上方动画完全同一思路:先看动画建立直觉 → 读文字巩固 → 关掉页面自己默写一遍代码,能写出来才算真的掌握

下一题 →11. 盛最多水的容器 ← 返回题库