在一个 2 x 3 的板上(board)有 5 块砖瓦,用数字 1~5 来表示, 以及一块空缺用 0 来表示。一次 移动 定义为选择 0 与一个相邻的数字(上下左右)进行交换.
最终当板 board 的结果是 [[1,2,3],[4,5,0]] 谜板被解开。
给出一个谜板的初始状态 board ,返回最少可以通过多少次移动解开谜板,如果不能解开谜板,则返回 -1 。
示例 1:
输入:board = [[1,2,3],[4,0,5]]
输出:1
解释:交换 0 和 5 ,1 步完成
示例 2:
输入:board = [[1,2,3],[5,4,0]]
输出:-1
解释:没有办法完成谜板
示例 3:
输入:board = [[4,1,2],[5,0,3]]
输出:5
解释:
最少完成谜板的最少移动次数是 5 ,
一种移动路径:
尚未移动: [[4,1,2],[5,0,3]]
移动 1 次: [[4,1,2],[0,5,3]]
移动 2 次: [[0,1,2],[4,5,3]]
移动 3 次: [[1,0,2],[4,5,3]]
移动 4 次: [[1,2,0],[4,5,3]]
移动 5 次: [[1,2,3],[4,5,0]]
提示:
board.length == 2
board[i].length == 3
0 <= board[i][j] <= 5
board[i][j] 中每个值都 不同
Please complete the following python code precisely.
class Solution:
def slidingPuzzle(self, board: List[List[int]]) -> int:
解答
为了解决这个问题,我们可以使用广度优先搜索(BFS)来遍历所有可能的移动,直到找到目标状态或确定无解。
首先,我们需要定义一个函数来检查给定的板状态是否为目标状态。然后,我们需要一个函数来生成所有可能的下一个状态,即移动0到其相邻位置。
最后,我们使用BFS来遍历所有状态,直到找到目标状态或遍历完所有可能的状态。
以下是完整的Python代码实现:
from collections import deque
class Solution:
def slidingPuzzle(self, board: List[List[int]]) -> int:
# 定义目标状态
target = [[1, 2, 3], [4, 5, 0]]
# 将二维列表转换为一维列表,方便后续操作
flat_board = [item for row in board for item in row]
# 定义四个方向的偏移量
directions = [(0, 1), (0, -1), (1, 0), (-1, 0)]
# 检查当前状态是否为目标状态
def is_target(board):
return board == target
# 获取0的位置
def get_zero_pos(board):
for i, num in enumerate(flat_board):
if num == 0:
return i // 3, i % 3
# 生成所有可能的下一个状态
def get_next_states(board):
x, y = get_zero_pos(board)
next_states = []
for dx, dy in directions:
nx, ny = x + dx, y + dy
if 0 <= nx < 2 and 0 <= ny < 3:
new_board = flat_board[:]
new_board[x * 3 + y], new_board[nx * 3 + ny] = new_board[nx * 3 + ny], new_board[x * 3 + y]
next_states.append(new_board)
return next_states
# 初始化BFS队列和访问集合
queue = deque([(flat_board, 0)]) # (state, steps)
visited = set([tuple(flat_board)])
while queue:
current_state, steps = queue.popleft()
if is_target(current_state):
return steps
for next_state in get_next_states(current_state):
if tuple(next_state) not in visited:
visited.add(tuple(next_state))
queue.append((next_state, steps + 1))
return -1 # 如果遍历完所有状态仍未找到目标状态,则返回-1
注意:在代码中,我将二维列表board转换为一维列表flat_board,以便更方便地进行索引和交换操作。同时,为了避免在访问集合中存储列表(因为列表是不可哈希的),我将列表转换为元组后再存入访问集合中。
此外,我还使用了一个队列queue来存储待处理的状态和对应的步数,以及一个访问集合visited来记录已经访问过的状态,以避免重复访问。
最后,当队列为空时,说明已经遍历完所有可能的状态,但仍未找到目标状态,此时返回-1表示无解。