返回

逐层深入,巧解 LeetCode 773:滑动谜题

前端

问题

在一个 2 x 3 的板上(board)有 5 块砖瓦,用数字 1~5 来表示, 以及一块空缺用 0 来表示. 一次移动定义为选择 0 与一个相邻的数字(上下左右)进行交换. 最终当板 board 的数字排布与目标数字排布 target 完全相同时,称之为求解成功.

给定一个初始排布的 board 和一个目标排布的 target,请你求出最少交换次数,以使 board 最终排布与 target 完全相同. 如果无法求解成功,则返回 -1.

解题思路

本题的解题思路是使用深度优先搜索(DFS)算法. DFS 是一种以深度优先的方式遍历状态空间树的算法. 在 DFS 中, 我们从某个初始状态开始, 然后逐层深入地探索所有可能的下一个状态, 直到找到目标状态或穷举所有可能的状态.

在 LeetCode 773 这道题中, 我们可以将 board 的排布看成一个状态, 然后根据 board 的当前排布, 将其所有可能的下一个排布都生成出来. 这样, 我们就可以构建一个状态空间树. 然后, 我们从初始状态开始, 使用 DFS 算法逐层深入地探索状态空间树, 直到找到目标状态或穷举所有可能的状态.

算法实现

def sliding_puzzle(board, target):
    """
    :type board: List[List[int]]
    :type target: List[List[int]]
    :rtype: int
    """
    # 将 board 和 target 转换为一维列表
    board_1d = [num for row in board for num in row]
    target_1d = [num for row in target for num in row]

    # 检查 board 和 target 是否具有相同的状态空间
    if sorted(board_1d) != sorted(target_1d):
        return -1

    # 定义 DFS 函数
    def dfs(current_state, step):
        # 将 current_state 转换为二维列表
        current_board = [[num for num in row] for row in current_state]

        # 检查 current_board 是否与 target 相同
        if current_board == target:
            return step

        # 寻找空缺位置
        zero_index = current_state.index(0)

        # 根据空缺位置生成所有可能的下一个状态
        next_states = []
        if zero_index % 3 > 0:
            next_states.append(swap(current_state, zero_index, zero_index - 1))
        if zero_index % 3 < 2:
            next_states.append(swap(current_state, zero_index, zero_index + 1))
        if zero_index > 2:
            next_states.append(swap(current_state, zero_index, zero_index - 3))
        if zero_index < 6:
            next_states.append(swap(current_state, zero_index, zero_index + 3))

        # 递归地探索所有可能的下一个状态
        min_step = float('inf')
        for next_state in next_states:
            if next_state not in visited:
                visited.add(next_state)
                step += 1
                next_step = dfs(next_state, step)
                if next_step != -1:
                    min_step = min(min_step, next_step)
                step -= 1
                visited.remove(next_state)

        # 返回最小交换次数
        return min_step if min_step != float('inf') else -1

    # 定义交换函数
    def swap(state, index1, index2):
        state[index1], state[index2] = state[index2], state[index1]
        return state

    # 初始化 visited 集合,用于记录已访问过的状态
    visited = set()

    # 从初始状态开始搜索
    result = dfs(board_1d, 0)

    return result

复杂度分析

  • 时间复杂度:本题的 DFS 算法的时间复杂度为 O(m^n), 其中 m 为状态空间的大小, n 为最长路径的长度. 在本题中, m = 5!, n = 12, 因此时间复杂度为 O(5! * 12).
  • 空间复杂度:本题的 DFS 算法的空间复杂度为 O(m + n), 其中 m 为状态空间的大小, n 为最长路径的长度. 在本题中, m = 5!, n = 12, 因此空间复杂度为 O(5! + 12).