青训营X豆包MarsCode 技术训练营第十三课 | 豆包MarsCode AI 刷题

66 阅读3分钟

第474题 监狱牢房变化问题

1.题目分析

该问题状态属于模拟类问题,需要模拟牢房的状态转变。每间牢房的状态(占用或空置)受到其左右相邻房间状态的影响,第一个和最后一个房间不变。我们需要:

  1. 根据初始状态cells模拟状态的变化。
  2. 确定了经过n天后的最终状态。

问题的重点在于:

  • 每天需要更新整个cells数据库。
  • n很大的时候,逐天模拟就会导致性能瓶颈。
  • 因此,需要利用状态变化的周期性进行优化。

2.解题思路

  • 逐日模拟状态变化

    • 根据规则生成下一天的状态。
    • 第一个和最后一个牢房不变,其余牢房状态通过比较左右邻居决定。
  • 优化国家计算

    • 如果n很大,可以观察是否状态重复。
    • 一旦检测到状态开始重复,就说明进入了周期,可以通过n % cycle_length直接确定剩余天数。
  • 终止条件

    • 若未出现周期,则模拟完整的n天。
    • 如果进入对应周期,直接计算剩余天数的状态,避免计算。

3.解题代码

def solution(cells: list, n: int) -> list:
    seen = {}  # 用于记录状态及其出现的天数
    is_fast_forwarded = False
    
    for day in range(n):
        if not is_fast_forwarded:
            state_tuple = tuple(cells)
            if state_tuple in seen:  # 如果状态已出现,进入循环模式
                cycle_length = day - seen[state_tuple]
                n %= cycle_length  # 剩下的天数通过循环优化
                is_fast_forwarded = True
            else:
                seen[state_tuple] = day

        if n > 0:  # 继续模拟剩余天数
            new_cells = [0] * len(cells)
            for i in range(1, len(cells) - 1):
                new_cells[i] = 1 if cells[i - 1] == cells[i + 1] else 0
            cells = new_cells
            n -= 1
    return cells
if __name__ == '__main__':
    print(solution(cells=[0, 1, 0, 1, 1, 0, 1], n=7) == [0, 1, 1, 1, 0, 1, 0])
    print(solution(cells=[1, 0, 0, 1, 0, 1, 0], n=12500) == [0, 1, 0, 0, 1, 0, 0])
    print(solution(cells=[1, 1, 0, 0, 0, 0, 1, 1, 1], n=6) == [0, 1, 0, 0, 1, 0, 0, 1, 0])
    print(solution(cells=[0, 0, 1, 1, 0, 0, 1, 1], n=10) == [0, 0, 1, 1, 1, 1, 0, 0])

4.模块解释

1.状态更新模块

new_cells = [0] * len(cells)
for i in range(1, len(cells) - 1):
    new_cells[i] = 1 if cells[i - 1] == cells[i + 1] else 0
cells = new_cells
  • 更新cells信息:

    • 使用新的仓库new_cells每天的变化结果。
    • 中间的牢房通过左右邻居的状态更新。
    • 第一个和最后一个牢房始终为0。

2.周期检测模块

state_tuple = tuple(cells)
if state_tuple in seen:
    cycle_length = day - seen[state_tuple]
    n %= cycle_length
    is_fast_forwarded = True
else:
    seen[state_tuple] = day
  • 使用哈希表seen检测状态是否重复:

    • 若当前状态已经出现过,则计算周期。
    • n % cycle_length减少模拟天数。

3.快速跳过周期模块

if not is_fast_forwarded:
    n %= cycle_length
    is_fast_forwarded = True
  • 通过跳过枢轴计算,效率显着提升。

4.模拟剩余天数模块

if n > 0:
    cells = new_cells
    n -= 1
  • 在优化后,继续模拟剩余的n天,方案完成

总结

  1. 优势

    • 利用周期性显著减少计算量,特别适合 n 非常大的情况。
    • 哈希表的使用避免了重复状态的冗余模拟。
  2. 性能

    • 最优情况下复杂度接近 O(k + n mod cycle_length),其中 kkk 是牢房数。
    • 最坏情况下复杂度为 O(k⋅n),仅在状态无周期时发生。
  3. 适用性

    • 该代码解决了任意大小的 ncells 状态输入,特别适合处理周期性问题。
    • 若周期较短,优化效果更显著。
  4. 输出准确性

    • 所有测试样例均能输出正确结果。周期检测有效避免了性能瓶颈,使得计算更加高效。