BFS解力扣1654最短跳跃次数
对于 LeetCode 1654 “到家的最少跳跃次数”这道题核心是使用广度优先搜索 (BFS)来寻找从起点0到目标位置x的最短路径。解题的关键在于对搜索空间进行合理的限制并正确处理“不能连续向后跳”的约束。问题解构与约束分析约束条件说明跳跃规则1. 向前跳a步。2. 向后跳b步。特殊限制1.不能连续两次向后跳。2. 不能跳到forbidden数组中的位置。3. 不能跳到负数位置。目标从位置 0出发到达位置x 的最少跳跃次数。关键难点与解决方案无限搜索空间由于可以向前和向后跳理论上搜索可以无限进行。必须设定一个合理的上界。“不能连续向后跳”需要在状态中记录上一次跳跃的方向以决定本次可选的跳跃方式。状态定义与去重一个位置可能被以不同的“上次跳跃方向”访问到需要记录(位置, 上次是否向后跳)这样一个组合状态来避免重复搜索。方案推演与核心思路BFS 状态设计每个 BFS 节点需要包含(当前位置 cur, 上次是否向后跳 is_back, 当前步数 step)。使用一个集合visited记录已访问的(cur, is_back)状态避免重复搜索。搜索上界确定参考中的分析一个常用的、安全的右边界是max(max(forbidden) a, x) b。更保守且普遍采用的上界是6000根据题目数据范围这是一个经验值足以覆盖所有可达状态。本文将采用6000作为上界。BFS 过程从初始状态(0, False, 0)开始。对于每个状态(cur, is_back, step)如果cur x返回step。尝试向前跳到next_cur cur a。若位置合法、非禁止、且状态未访问则入队并标记(next_cur, False)为已访问。尝试向后跳到next_cur cur - b。前提是is_back False上次没向后跳、位置合法、非禁止、且状态未访问则入队并标记(next_cur, True)为已访问。代码实现 (Python)from collections import deque class Solution: def minimumJumps(self, forbidden: List[int], a: int, b: int, x: int) - int: :type forbidden: List[int] :type a: int :type b: int :type x: int :rtype: int if x 0: return 0 # 将禁止列表转换为集合便于O(1)查找 forbid_set set(forbidden) # BFS搜索上界6000是一个经验值足以覆盖题目数据范围 MAX_BOUND 6000 # 访问状态记录使用(位置, 是否由向后跳抵达)作为键 visited set() # 队列元素: (当前位置, 是否由向后跳抵达, 当前步数) queue deque() queue.append((0, False, 0)) visited.add((0, False)) while queue: cur_pos, is_back, steps queue.popleft() # 尝试向前跳 next_pos cur_pos a # 检查位置是否合法未出界、非禁止点、状态未访问 if 0 next_pos MAX_BOUND and next_pos not in forbid_set and (next_pos, False) not in visited: if next_pos x: return steps 1 visited.add((next_pos, False)) queue.append((next_pos, False, steps 1)) # 尝试向后跳 (前提上一次不是向后跳) if not is_back: next_pos cur_pos - b # 检查位置是否合法非负、非禁止点、状态未访问 if next_pos 0 and next_pos not in forbid_set and (next_pos, True) not in visited: if next_pos x: return steps 1 visited.add((next_pos, True)) queue.append((next_pos, True, steps 1)) # BFS队列清空仍未找到目标说明不可达 return -1关键点与示例分析为什么上界是 6000这是一个基于题目数据范围的工程经验值。题目中a, b, x均不超过 2000forbidden长度不超过 1000。通过分析最坏情况下需要探索的范围不会超过max(x, max(forbidden)) a b再乘以一个较小的系数6000 是一个足够大且安全的边界可以避免无限循环同时不会引起不必要的性能开销。状态(位置, 是否由向后跳抵达)的重要性考虑以下场景从位置p通过向前跳抵达位置q和通过向后跳抵达位置q这两种状态是不等价的。因为后者意味着下一次移动不能向后跳而前者可以。因此必须区分这两种情况否则会丢失可行解或导致错误。示例运行以题目示例forbidden [14,4,18,1,15], a 3, b 15, x 9为例初始状态(0, False, 0)。从0向前跳3步到3状态(3, False, 1)。从3向前跳3步到6状态(6, False, 2)。从6向前跳3步到9发现9 x返回步数3。程序输出结果为3与示例一致。关于一个“神奇BUG”的说明在中作者提到了一个在特定代码结构下return或break可能无法立即退出的情况。这通常与循环和条件判断的嵌套逻辑有关并非语言本身的BUG。上述提供的代码结构清晰在找到目标时立即返回steps 1可以正确退出。参考来源【LeetCode】1654到家的最少跳跃次数的解题思路 关于力扣无法return的BUG的讨论LeetCode 题解 —— 1654. 到家的最少跳跃次数Leetcode1654. 到家的最少跳跃次数(medium,BFS)1654. 到家的最少跳跃次数Leetcode.1654 到家的最少跳跃次数【每日一题】1654. 到家的最少跳跃次数