首先定义了一个 slidingPuzzle 方法,接收一个二维数组 board 作为参数,表示初始的拼图板状态,然后返回一个整数表示移动到目标状态所需的最小步数。
初始化了一个二维数组 neighbor,用于记录每个数字在一维字符串中的相邻索引,这是为了在移动数字时判断合法性。
创建了一个队列 q 和一个哈希集 visited。队列用于广度优先搜索(BFS)时存储待处理的拼图板状态,哈希集用于记录已经访问过的拼图板状态,避免重复访问。
将初始的二维数组转换成一维字符串,并将其作为起始状态加入队列,并标记为已访问。
在一个循环中,不断从队列中取出拼图板状态进行处理,直到队列为空。在每一步中,先判断当前状态是否为目标状态,若是则返回步数。
若当前状态不是目标状态,则遍历每个数字的相邻索引,尝试将数字0与相邻数字交换位置,生成新的拼图板状态。
如果新状态未被访问过,则将其加入队列,并标记为已访问。
最后返回 -1,表示无法达到目标状态。
class Solution {
public int slidingPuzzle(int[][] board) {
int m = 2;
int n = 3;
StringBuilder sb = new StringBuilder();
String target = "123450";
// 将2 x 3数组转换为字符串 作为BFS的起点局面
for(int i = 0; i < board.length; i++){
for(int j = 0; j < board[0].length; j++){
sb.append(board[i][j]);
}
}
String start = sb.toString();
// 记录一维字符串的相邻索引
int[][] neighbor = new int[][]{
{1,3},
{0,4,2},
{1,5},
{0,4},
{3,1,5},
{4,2}
};
Queue<String> q = new LinkedList<>();// 双向链表模拟队列
HashSet<String> visited = new HashSet<>();
// 从起点开始搜索
q.offer(start);
visited.add(start);// 标记已经访问了
int step = 0;
while(!q.isEmpty()){
int sz = q.size();
for(int i = 0; i < sz; i++){
String cur = q.poll();
// 判断是否到达目标局面
if(target.equals(cur)){
return step;
}
// 没有到达 搜索下一种字符串局面 然后入队
// 通过计算索引0 的周围索引 然后移动 判断新的字符串是否出现过
// 新的字符串没有出现过 直接入队
// 找到数字0的索引
int id = 0;
for(;cur.charAt(id) != '0'; id++);
// 将数字0和相邻的数字交换位置
for(int adj: neighbor[id]){
// 遍历数字0 的相邻数字的索引
String new_board = swap(cur.toCharArray(),adj,id);
// 判断新的字符串是否已经出现过
if(!visited.contains(new_board)){
// 如果没有出现过 直接入队
q.offer(new_board);
visited.add(new_board);// 标记已经出现过
}
}
}
step++;
}
return -1;// 没找到 直接-1
}
// 交换一个字符串的两个字符
private String swap(char[] chars,int i,int j){
char temp = chars[i];
chars[i] = chars[j];
chars[j] = temp;
return new String(chars);
}
}