高效求解轮盘弹跳问题:基于循环节检测的 O(n) 优化算法

本文介绍如何将时间复杂度从 o(b) 降至 o(n) 来解决 hackerrank 上的“movement slots”问题——通过检测状态序列中的循环节(intro + cycle),避免对超大步数 b(如 10¹²)进行暴力模拟。

本文介绍如何将时间复杂度从 o(b) 降至 o(n) 来解决 hackerrank 上的“movement slots”问题——通过检测状态序列中的循环节(intro + cycle),避免对超大步数 b(如 10¹²)进行暴力模拟。

在轮盘弹跳问题中,一个球从初始槽位 a 出发,每经过一次弹跳,就根据当前槽位 i 对应的偏移量 slots[i] 跳转到新位置:
$$
\text{next} = (i + \text{slots}[i]) \bmod n
$$
其中 n 是槽位总数(索引为 0 到 n-1)。当查询次数 q 较少但单次弹跳步数 b 极大(例如 $10^{12}$)时,朴素的 for _ in range(b) 模拟必然超时。

根本优化思路是:状态空间有限(仅 n 个可能槽位),因此球的位置序列必在有限步内进入循环。该序列结构为经典的「ρ 形」(Rho-shaped):一段非重复的前导(intro)后接一个纯循环(cycle)。例如:

a → s₁ → s₂ → … → sₓ → c₁ → c₂ → … → c_y → c₁ → …
           ↑_____________↑
                cycle starts here
  • X:intro 长度(首次出现重复前的步数)
  • Y:cycle 长度(循环节周期)

一旦确定 X 和 Y,对任意 b 的最终槽位可分两步计算:

  • 若 b ≤ X:直接模拟 b 步;
  • 若 b > X:先走 X 步到达 cycle 入口,再走 (b − X) % Y 步(跳过完整循环轮数)。

✅ 实现要点(单次查询 O(n))

使用哈希表记录每个槽位首次访问的步数,遍历时一旦遇到已见槽位,即可立即提取 X 和 Y:

百宝箱

百宝箱是支付宝推出的一站式AI原生应用开发平台,无需任何代码基础,只需三步即可完成AI应用的创建与发布。

def final_slot_optimized(a, b, slots):
    n = len(slots)
    if b == 0:
        return a

    # 记录每个槽位首次出现的步数
    first_seen = {}
    path = []  # 存储访问路径(槽位序列),索引即步数
    current = a

    # 模拟直到发现重复或走完 b 步
    step = 0
    while step  b:
        return path[b]

    # 发现循环:first_seen[current] 是 cycle 入口步数 X
    X = first_seen[current]
    Y = step - X  # 当前步数 - 入口步数 = cycle 长度

    if b <= X:
        return path[b]
    else:
        # 走 X 步到 cycle 入口,再走剩余偏移
        offset = (b - X) % Y
        return path[X + offset]

⚠️ 注意事项与边界处理

  • 模运算安全:slots[i] 可为负数,Python 中 (i + slots[i]) % n 自动处理负模(如 -1 % 5 == 4),无需额外修正。
  • 索引一致性:题目未明确槽位编号是否从 0 或 1 开始。示例代码使用 0-based,若输入为 1-based(如 a=1),需统一减 1 处理。
  • 空间优化:path 数组最坏存 n+1 项,空间复杂度 O(n),可接受;若内存极端受限,可在检测到 cycle 后仅缓存 cycle 区间 [X, step)。
  • 多查询场景:若多个查询共享同一 slots 数组,可预计算所有起始点的循环信息(需 O(n²) 预处理),但通常 q 较小,对每个查询独立检测更简洁。

? 总结

本方案将单次查询时间复杂度从 O(b) 严格降为 O(n),彻底解决 b = 10^12 类超大输入瓶颈。核心在于利用有限状态机的必然循环性,通过一次正向遍历完成 intro/cycle 识别,再用模运算跳过冗余周期。该思想广泛适用于图上路径、迭代函数、链表环检测等场景,是算法优化中「找规律替代硬算」的经典范式。

相关推荐:

基于分支定界法的带卡车容量约束的运输问题求解教程

本文介绍如何将经典运输问题扩展为考虑6吨卡车整数装载限制的混合整数线性规划(milp)问题,并利用分支定界法(由求解器自动执行)求得全局最优解,重点在于建模技巧与变量耦合设计。 本文介绍如何将经典运输问题扩展为考虑6吨卡车整数装载限制的混合整数线性规划(milp)问题,并利用分支定界法(由求解器自动...

如何在Python中通过计算欧氏距离实现基础的最近邻分类算法?

欧氏距离计算函数怎么写才不出错? 直接用math.sqrt和sum手动算平方和开方最稳妥,避免依赖未安装的库。常见错误是传入维度不一致的向量,比如训练样本是4维,测试样本只给了3个值——运行时会报IndexError或得到错误结果。 实操建议: 在计算前用len(vec1)==len(vec2)做校...

如何使用Python中的Isolation Forest算法实现生产环境的异常检测?

IsolationForest在生产环境不适合直接用于高吞吐、低延迟的实时流式场景,因其为无监督批处理算法,需完整训练集且无法在线更新模型,实际应采用周期性离线打分或结合轻量代理模型实现近实时响应。 IsolationForest在生产环境是否适合实时异常检测? 不适合直接用于高吞吐、低延迟的实时流...

如何用Python高效读取GB级别的大容量文本文件?

直接用open().readlines()会触发MemoryError,因其一次性将整个文件加载进内存生成列表;真正高效的是forlineinopen(),它利用文件迭代器按需读取,每次仅加载一行,实现常数内存占用。 直接用open().readlines()会触发MemoryError,尤其在内存...