在一个 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
解释:没有办法完成谜板
题解:BFS广度优先搜索算法
这道题是一个是一个从初始状态转换到目标状态的问题
利用广度优先搜索算法来找出从初始状态到目标状态的最小移动次数。使用BFS算法时,需要用到两种数据结构,一是队列queue,用于保存当前第一次被搜索到的状态,二是哈希表HashMap,用于保存已经搜索过一次的状态,防止重复搜索。
为了便于队列以及哈希表保存状态,我们将当前的状态数组转换为字符串,比如 [[1,2,3],[4,5,0]]就可以转换为 “123450”
具体地,我们在一开始将初始状态(start,0)加入队列,并使用该队列进行广度优先搜索。在搜索的过程中,设当前搜索到的状态为pos,操作的次数为 steps,我们可以枚举 pos通过一次操作得到的状态。设其中的某个状态为 nextPos,如果其没有被搜索过,我们就将 (nextPos, steps + 1) 加入队列。如果搜索到了target,我们就返回其对应的操作次数。
class Solution {
int[][]nextIndex=new int[][]{{1,3},{0,2,4},{1,5},{0,4},{1,3,5},{2,4}};
public int slidingPuzzle(int[][] board) {
StringBuilder str=new StringBuilder();
for(int[]x:board){
for(int y:x){
str.append(y);
}
}
String start=str.toString();
if(start.equals("123450")){
return 0;
}
Queue<String>queue=new LinkedList<>();
HashSet<String>searched=new HashSet<>();
queue.add(start);
searched.add(start);
int steps=0;
while (!queue.isEmpty()){
steps++;
int size= queue.size();
for(int i=0;i<size;i++){
String peek= queue.poll();
assert peek != null;
for(String x:getNext(peek)){
if(!searched.contains(x)){
if(x.equals("123450")){
return steps;
}
searched.add(x);
queue.add(x);
}
}
}
}
return -1;
}
public List<String>getNext(String pos){
List<String>res=new ArrayList<>();
char[]chars=pos.toCharArray();
int i=pos.indexOf('0');
for(int x:nextIndex[i]){
swap(chars,x,i);
res.add(new String(chars));
swap(chars,x,i);
}
return res;
}
public void swap(char[]pos,int x,int y){
char temp=pos[x];
pos[x]=pos[y];
pos[y]=temp;
}
}