- 问题描述
在一个 2 x 3 的板上(
board
)有 5 块砖瓦,用数字1~5
来表示, 以及一块空缺用0
来表示.一次移动定义为选择
0
与一个相邻的数字(上下左右)进行交换.最终当板
board
的结果是[[1,2,3],[4,5,0]]
谜板被解开。给出一个谜板的初始状态,返回最少可以通过多少次移动解开谜板,如果不能解开谜板,则返回 -1 。
- 示例
输入:board = [[1,2,3],[4,0,5]] 输出:1 解释:交换 0 和 5 ,1 步完成 输入:board = [[1,2,3],[5,4,0]] 输出:-1 解释:没有办法完成谜板 输入: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 = [[3,2,4],[1,5,0]] 输出:14
- 提示
board
是一个如上所述的 2 x 3 的数组.board[i][j]
是一个[0, 1, 2, 3, 4, 5]
的排列.
- 解读
1、广度优先搜索(bfs)。见 【模板】广度优先搜索(bfs)
- 代码
class Data {
int[][] mat;
int val;
int len;
public Data(int[][] mat, int len) {
this.mat = mat;
this.val = toHash(this.mat);
this.len = len;
}
}
Queue<Data> datas = new LinkedList<>();
Set<Integer> sets = new HashSet<>();
public int toHash(int[][] mat) {
int m = mat.length;
int n = mat[0].length;
int sum = 0;
int index = 1;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
sum += mat[i][j] * index;
index = index * 10;
}
}
return sum;
}
public int[][] change(int[][] mat, int s, int t, int op) { // s, t 改变, op 0,上,1,下,2,左,3右
int m = mat.length;
int n = mat[0].length;
int cs = s;
int ct = t;
if (op == 0) {
cs--;
} else if (op == 1) {
cs++;
} else if (op == 2) {
ct--;
} else {
ct++;
}
if (cs < 0 || cs >= m || ct < 0 || ct >= n) {
return null;
}
int[][] nm = new int[m][n];
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
nm[i][j] = mat[i][j];
}
}
// s,t 与 cs, ct 交换
int p = nm[s][t];
nm[s][t] = nm[cs][ct];
nm[cs][ct] = p;
return nm;
}
public void addData(Data data) { // 产生下一个。
int[][] mat = data.mat;
int m = mat.length;
int n = mat[0].length;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (mat[i][j] == 0) {
for (int k = 0; k < 4; k++) {
int[][] nm = change(mat, i, j, k);
if (nm == null) {
continue;
}
Data d = new Data(nm, data.len + 1);
if (sets.contains(d.val)) {
continue;
}
sets.add(d.val);
datas.add(d);
}
return;
}
}
}
}
public int slidingPuzzle(int[][] board) {
Data data = new Data(board, 0);
datas.offer(data);
sets.add(data.val);
while (!datas.isEmpty()) {
data = datas.poll();
if (data.val == 54321) {
return data.len;
}
this.addData(data);
}
return -1;
}