Python算法训练序列

双指针与滑动窗口 · Unit 03

← Unit 02
167
LeetCode 167Two Sum II · 两数之和 II

排序不是背景条件,
而是每次安全排除一端的证据。

如果当前两端之和偏小,最小值不可能与区间内任何更小的右值达到目标,因此可以排除左端;如果当前和偏大,最大值不可能与区间内任何更大的左值达到目标,因此可以排除右端。

LeetCode #167 原题内容 中文转述 · 示例、约束与提交签名

题目要求

给定一个按非递减顺序排列、题意上使用 1-based 下标的整数数组 numbers,找到两个不同位置,使对应元素之和等于 target。返回这两个位置组成的数组,并保证恰好存在一个解。算法只能使用常数额外空间。

class Solution: def twoSum(self, numbers: List[int], target: int) -> List[int]: # 返回 [left + 1, right + 1]

约束

  • 2 ≤ len(numbers) ≤ 30000
  • -1000 ≤ numbers[i], target ≤ 1000
  • numbers 按非递减顺序排列;
  • 恰好存在一个答案,且同一元素不能使用两次。

示例

numbers = [2,7,11,15], target = 9
输出:[1,2]
numbers = [2,3,4], target = 6
输出:[1,3]
numbers = [-1,0], target = -1
输出:[1,2]

索引提醒

Python列表内部仍用 0-based 索引;只有返回答案时才统一加 1。

1. 体验组合枚举
2. 发现单调方向
3. 证明安全排除
4. 代码联动
5. 批量计数迁移
演示:numbers = [1,2,4,6,8,11],target = 10等待判断
numbers[left]1
+
numbers[right]11
=
current_sum12
12 > 10:和偏大

当前循环不变量

若答案尚未找到,则答案一定仍位于[left, right]的未排除区间中。

当前移动依据

当前和偏大时,排除右端;当前和偏小时,排除左端。

left0
right5
当前和12
已排除端点0
返回下标—
候选配对空间
每次排除一个端点,等价于一次删除一整行或一整列候选配对。
补全 LeetCode 提交代码卡住可查看参考答案
class Solution:
def twoSum(self, numbers: List[int], target: int) -> List[int]:
left, right =
while left < right:
current_sum =
if current_sum == target:
return
if current_sum < target:
else:
class Solution: def twoSum(self, numbers: List[int], target: int) -> List[int]: left, right = 0, len(numbers) - 1 while left < right: current_sum = numbers[left] + numbers[right] if current_sum == target: return [left + 1, right + 1] if current_sum < target: left += 1 else: right -= 1
为什么不需要哈希表?普通两数之和依赖哈希保存历史;本题已经排序,可以利用两端和的单调变化直接排除候选,达到 O(n) 时间和 O(1) 额外空间。
代码—指针—候选空间联动轨迹:[1,2,4,6,8,11], target=10
1class Solution:
2 def twoSum(self, numbers: List[int], target: int) -> List[int]:
3 left, right = 0, len(numbers) - 1
4 while left < right:
5 current_sum = numbers[left] + numbers[right]
6 if current_sum == target:
7 return [left + 1, right + 1]
8 if current_sum < target:
9 left += 1
10 else:
11 right -= 1
逐行播放,观察每次比较如何删除一批候选配对。
完成代码联动后进入批量计数迁移补全正确、查看答案或播放完整轨迹后解锁。

迁移题:LeetCode #2824 统计和小于目标值的数对

先排序。如果 nums[left] + nums[right] < target,那么固定left时,left与 left+1...right 的所有配对都合法,可以一次加入 right-left 个答案;否则令right左移。

本单元形成的算法Skill

在有序数组中,两端元素之和随指针移动具有单调性。当前和偏小时,排除最小左端;当前和偏大时,排除最大右端。双指针的关键不是“从两端开始”,而是每次移动都能证明被排除端点不可能参与答案。

LeetCode #167有序性相向双指针单调排除1-based返回O(n) / O(1)
#125 已完成镜像比较与字符过滤
#283 已完成同向读写指针
#167 当前:单调排除有序数组两端收缩
#15 下一单元固定一个数+双指针+去重