题目
在一个 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] 的排列.
题解
BFS搜索
class Solution {
public int slidingPuzzle(int[][] board) {
Set<String> visited = new HashSet<>();
Queue<String> queue = new LinkedList<>();
String str = boardToString(board);
queue.offer(str);
int step = 0;
while(!queue.isEmpty()){
int size = queue.size();
for(int i = 0; i < size; i++){
String s = queue.poll();
if("123450".equals(s)) return step;
if(visited.contains(s)) continue;
int index = s.indexOf("0");
visited.add(s); // 访问标记
if(index != 0 && index != 3){ // 向左换
queue.offer(s.substring(0, index - 1) + "0" + s.charAt(index - 1) + s.substring(index + 1)); //换左边
}
if(index == 0 || index == 3 || index == 1){ // 向右换
queue.offer(s.substring(0, index) + s.charAt(index + 1) + "0" + s.substring(index + 2)); //换右边
}
if(index == 4){ // 向右换
queue.offer(s.substring(0, index) + s.charAt(index + 1) + "0"); //换右边
}
if(index < 3){ // 向下换
queue.offer(s.substring(0, index) + s.charAt(index + 3) + s.substring(index + 1, index + 3) + "0" + s.substring(index + 4));
}else{ //向上换
queue.offer(s.substring(0, index - 3) + "0" + s.substring(index - 2, index) + s.charAt(index - 3) + s.substring(index + 1));
}
}
step++;
}
return -1;
}
private String boardToString(int[][] board){
StringBuffer sb = new StringBuffer();
for(int i = 0; i < 2; i++){
for(int j = 0; j < 3; j++)
sb.append(String.valueOf(board[i][j]));
}
return sb.toString();
}
}
官方解法,差不多
class Solution {
int[][] neighbors = {{1, 3}, {0, 2, 4}, {1, 5}, {0, 4}, {1, 3, 5}, {2, 4}}; //直接写出可交换的相邻位置
public int slidingPuzzle(int[][] board) {
StringBuffer sb = new StringBuffer();
for(int i = 0; i < 2; i++){
for(int j = 0; j < 3; j++)
sb.append(board[i][j]);
}
Set<String> visited = new HashSet<>();
Queue<String> queue = new LinkedList<>();
String init = sb.toString();
if("123450".equals(init)) return 0;
queue.offer(init);
visited.add(init);
int step = 0;
while(!queue.isEmpty()){
++step;
int size = queue.size();
for(int i = 0; i < size; i++){
String status = queue.poll();
for(String nextStatus : get(status)){
if(!visited.contains(nextStatus)){
if("123450".equals(s)) return step;
queue.offer(nextStatus);
visited.add(nextStatus);
}
}
}
}
return -1;
}
// 枚举 status 通过一次交换操作得到的状态
public List<String> get(String status) {
List<String> ret = new ArrayList<String>();
char[] array = status.toCharArray();
int x = status.indexOf('0');
for (int y : neighbors[x]) {
swap(array, x, y);
ret.add(new String(array));
swap(array, x, y);
}
return ret;
}
public void swap(char[] array, int x, int y) {
char temp = array[x];
array[x] = array[y];
array[y] = temp;
}
}