目录
跳蚤跳跃问题:带约束的最短路径搜索详解
题目描述
假设有一只跳蚤,它的家在数轴上的某个位置 x。跳蚤从位置 0 出发,目标是跳到它的家。跳跃规则如下:
- 跳蚤可以向前跳恰好 a 个位置(往右跳)。
- 跳蚤可以向后跳恰好 b 个位置(往左跳)。
- 不能连续两次向后跳。
- 跳蚤不能跳到 forbidden 数组中指定的位置。
- 跳蚤可以跳出它家的位置(即可以跳过 x),但不能跳到负数的位置。
给定整数数组 forbidden
,表示跳蚤不能跳到的位置,以及整数 a、b、x,请返回跳蚤跳到 x 的最少跳跃次数。如果无法到达,返回 -1。
题目难点与分析
本题是一个带有复杂约束的最短路径搜索问题:
- 状态限制:跳蚤不能连续两次往后跳,这限制了跳跃的连续模式。
- 禁止跳跃位置:
forbidden
数组给定了禁止跳跃的位置,跳到这些位置无效。 - 空间范围限制:数轴是无限的,跳蚤可以跳出 xx,但不能跳到负数,搜索范围不确定。
- 多状态变量:不仅要考虑当前位置,还要考虑上一次跳跃是否为后跳。
这些因素使得简单的 BFS 直接用位置做状态不够,需要额外状态信息来判断“是否连续后跳”。
解题思路
状态定义
用 (pos, back)
来表示跳蚤的状态:
pos
表示当前跳蚤所在位置back
是布尔值,表示跳蚤上一次是否刚后跳(True 表示是后跳,False 表示非后跳)
状态转移
从状态 (pos, back)
可以跳跃到:
- 向前跳:跳到
pos + a
,后退状态设为False
。 - 向后跳:如果上一次不是后跳 (
back == False
),则可以跳到pos - b
,后退状态设为True
。
约束判断
- 新位置不能是 forbidden 中的点
- 新位置不能小于 0
- 跳跃次数最小,因此采用 BFS 遍历,保证首次到达目标即为最短跳跃次数。
限制搜索范围
理论上,跳蚤可以无限向前跳,为防止搜索空间过大,我们定义一个最大边界 limit
:
limit=max(max(forbidden)+a+b,x+b)
即最大禁止位置附近再多跳几个单位,或目标位置附近稍作缓冲。
代码实现(Python)
from collections import deque
class Solution:
def minimumJumps(self, forbidden: list[int], a: int, b: int, x: int) -> int:
forbidden_set = set(forbidden)
limit = max(max(forbidden, default=0) + a + b, x + b)
# BFS 队列元素格式:(位置, 是否刚后跳, 跳跃次数)
queue = deque([(0, False, 0)])
visited = set([(0, False)]) # 记录访问状态,避免重复
while queue:
pos, back, steps = queue.popleft()
# 到达目标
if pos == x:
return steps
# 向前跳
forward = pos + a
if forward <= limit and forward not in forbidden_set and (forward, False) not in visited:
visited.add((forward, False))
queue.append((forward, False, steps + 1))
# 向后跳(仅当上一步不是后跳)
backward = pos - b
if not back and backward >= 0 and backward not in forbidden_set and (backward, True) not in visited:
visited.add((backward, True))
queue.append((backward, True, steps + 1))
return -1
复杂度分析
- 时间复杂度:
搜索范围被限制为limit
,最多访问每个位置两次(后退状态 True 或 False),所以时间复杂度约为 O(limit)。 - 空间复杂度:
需要存储访问状态和 BFS 队列,空间复杂度也为 O(limit)。
示例说明
假设输入:
forbidden = [14, 4, 18, 1, 15]
a = 3
b = 15
x = 9
- 起点是0,目标9
- forbidden禁止跳的点包括1,4,14,15,18
- 跳跃规则:前跳3步,后跳15步,且不能连续后跳
BFS遍历过程(简化):
- 起点0,后退状态False,步数0
- 可以向前跳到3,向后跳不可行(会到负数)
- 从3开始,向前跳6,向后跳0(不连续后退条件满足)
- 从6开始,向前跳9(达目标),完成
最短跳跃次数为3次。
小结与拓展
- 本题典型应用了 BFS 寻找带额外状态的最短路径问题。
- 需要额外状态记录来解决“不能连续后跳”的限制。
- 通过合理限定搜索边界,有效避免爆炸搜索空间。
- 代码实现中,使用集合
visited
存储(位置, 是否后跳)
状态,保证了 BFS 的正确性与效率。