题目描述
一个升序数组里找两个数,使它们相加等于 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](看清题目下标基准)
以上文字与上方动画完全同一思路:先看动画建立直觉 → 读文字巩固 → 关掉页面自己默写一遍代码,能写出来才算真的掌握。