返回

转动开锁——广度优先搜索的妙用

前端

转动开锁——别出心裁的密码挑战

设想这样一个情境:您置身于一个房间,面前有一扇转盘锁,四个圆形拨轮紧密相扣,阻挡了您的去路。每个拨轮上有 10 个数字,从 0 到 9,您需要通过转动拨轮,使它们排列成特定的顺序,才能打开锁。

广度优先搜索——抽丝剥茧的探索之道

广度优先搜索(BFS)是一种算法,它从图的根节点开始,一层一层地探索图的各个节点。在 BFS 中,所有同一层级的节点都会在同一时间被访问,然后才会继续探索下一层的节点。

在「752. 打开转盘锁」中,我们可以将转盘锁的状态视为一个图,图中的每个节点表示一种可能的转盘锁状态,而图中的每条边表示从一种状态到另一种状态的转换。

广度优先搜索从初始状态开始,将所有相邻状态加入队列,然后依次访问这些状态。如果某个相邻状态是目标状态,那么搜索结束;否则,将该状态的所有相邻状态加入队列,继续搜索。

模运算——环环相扣的数字世界

在「752. 打开转盘锁」中,转盘锁的每个拨轮上有 10 个数字,从 0 到 9。当某个拨轮转动到 9 后,再转动一次就会回到 0。同理,当某个拨轮转动到 0 后,再转动一次就会回到 9。

这种数字的循环特性可以用模运算来表示。模运算是一种数学运算,它可以计算两个数相除后的余数。在「752. 打开转盘锁」中,我们可以使用模运算来计算转盘锁的每个拨轮在转动后所处的状态。

算法实现——步步为营的探索之旅

def openLock(deadends, target):
    # 初始化队列和已访问状态集合
    queue = [(0, 0, 0, 0)]
    visited = set()

    # 广度优先搜索
    while queue:
        # 从队列中取出当前状态
        state = queue.pop(0)

        # 如果当前状态是目标状态,则返回步数
        if state == target:
            return steps

        # 将当前状态加入已访问状态集合
        visited.add(state)

        # 遍历当前状态的四个拨轮
        for i in range(4):
            # 将当前拨轮向左转动一位
            new_state = (state[i] - 1) % 10

            # 将当前拨轮向右转动一位
            new_state = (state[i] + 1) % 10

            # 如果新状态不在已访问状态集合中,则将其加入队列
            if new_state not in visited:
                queue.append(new_state)

    # 如果没有找到目标状态,则返回 -1
    return -1

结语

广度优先搜索算法以其简单易懂的实现方式,为解决图论问题提供了高效而强大的工具。「752. 打开转盘锁」一题巧妙地融合了广度优先搜索和模运算,为我们展示了算法在解决实际问题中的应用魅力。