一、题目
在一个 2 x 3
的板上(board)
有 5
块砖瓦,用数字 1~5
来表示, 以及一块空缺用 0
来表示.
一次移动定义为选择 0
与一个相邻的数字(上下左右)进行交换.
最终当板 board
的结果是 [[1,2,3],[4,5,0]]
谜板被解开。
给出一个谜板的初始状态,返回最少可以通过多少次移动解开谜板,如果不能解开谜板,则返回-1
。
点击查看原题
难度级别: 困难
二、思路
1)哈希表+BFS
思路跟752
题思路大致相似。
根据当前状态,推断出接下来可能的每一步,并将访问过的状态记录下来,防止多次访问已经访问过的状态,根据状态进行BFS
。
如何代表每一种状态?
在这里的思路是使用一个int
型,由于是六位数,远小于int
型的最大值,可以通过每一个元素占一个十进制位进行表示,确保每个状态都有一个独立的int
数值表示。
如何找到下一步的状态?
此处根据表示状态的int
还原位二维数组,找到零的位置后,根据零可以与相邻数字交换,从而进行记录一步交换的状态。
三、代码
1)哈希表+BFS
class Solution {
public int slidingPuzzle(int[][] board) {
int target = 123450;
Set<Integer> visited = new HashSet();
int initalLoc = getStatuInt(board);
if (initalLoc == target) { // 查看起点是否目标满足要求
return 0;
}
visited.add(initalLoc);
int step = 1;
Queue<Integer> q = new LinkedList();
q.add(initalLoc);
while (!q.isEmpty()) {
int len = q.size();
while (len-- > 0) { // 每次将一步的所有可能性遍历完
int val = q.poll();
List<Integer> nextSteps = getNextStep(val); // 获取所有下一步的可能性
for (int nextStep : nextSteps) {
if (visited.contains(nextStep)) { // 访问过的状态跳过
continue;
}
if (nextStep == target) {
return step;
}
q.add(nextStep);
visited.add(nextStep);
}
}
step++;
}
return -1;
}
private List<Integer> getNextStep(int val) {
int[][] board = new int[2][3];
int offset = 100000;
int zeroRow = 0, zeroCol = 0;
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board[0].length; j++) {
board[i][j] = (val/offset) % 10;
offset /= 10;
if (board[i][j] == 0) { // 找到0所在的位置
zeroRow = i;
zeroCol = j;
}
}
}
List<Integer> ans = new ArrayList();
int[][] directs = {{0, 1}, {1, 0}, {-1, 0}, {0, -1}};
for (int[] direct : directs) {
int newVal = swapGetStatuIntAndRestore(board, zeroRow, zeroCol, zeroRow + direct[0], zeroCol + direct[1]);
if (newVal != -1) {
ans.add(newVal);
}
}
return ans;
}
private int swapGetStatuIntAndRestore(int[][] board, int zeroRow, int zeroCol, int anthRow, int anthCol) {
if (anthRow >= board.length || anthRow < 0 || anthCol >= board[0].length || anthCol < 0) {
return -1;
}
swap(board, zeroRow, zeroCol, anthRow, anthCol);
int ans = getStatuInt(board);
swap(board, zeroRow, zeroCol, anthRow, anthCol);
return ans;
}
private void swap(int[][] board, int zeroRow, int zeroCol, int anthRow, int anthCol) {
int t = board[zeroRow][zeroCol];
board[zeroRow][zeroCol] = board[anthRow][anthCol];
board[anthRow][anthCol] = t;
}
private int getStatuInt(int[][] board) {
int ans = 0;
int offset = 100000;
for (int[] row : board) {
for (int i : row) {
ans += offset * i;
offset /= 10;
}
}
return ans;
}
}
数组中元素个数为n
,时间复杂度为O(n*n!)
,空间复杂度为O(n*n!)