算法题(程序员面试宝典)
解题思路主要来源于leetcode官方与《程序员面试宝典》&labuladong
773. 滑动谜题
在一个 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
class Solution {
public int slidingPuzzle(int[][] board) {
//将此问题转换为BFS算法问题 即找最短路径
//首先将二维数组转换为一维数组
//m行
int m = board.length;
//n列
int n = board[0].length;
StringBuilder startSb = new StringBuilder();
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
startSb.append(board[i][j]);
}
}
String start = startSb.toString();
String target = "123450";
//记录步数
int step = 0;
//每一个索引位置的上下左右的索引位置
LinkedHashMap<Integer,LinkedList<Integer>> neighbor = getNeighborIndex(m,n);
Queue<String> q = new LinkedList<>();
HashSet<String> visited = new HashSet<>();
q.offer(start);
visited.add(start);
while(!q.isEmpty()){
int size = q.size();
for(int i=0;i<size;i++){
String cur = q.poll();
if(cur.equals(target))
return step;
//查找当前cur的0位置
char[] curArray = cur.toCharArray();
int j=0;
for(;j<curArray.length;j++){
if(curArray[j]=='0'){
break;
}
}
//将移动一次后的加过加入至队中
LinkedList<Integer> allIndex = neighbor.get(j);
for(Integer index:allIndex){
char[] newCurArray = new char[curArray.length];
for(int k=0;k<newCurArray.length;k++){
newCurArray[k] = curArray[k];
}
//交换 index 和 j 位置的元素
char temp = newCurArray[index];
newCurArray[index] = newCurArray[j];
newCurArray[j] = temp;
String tempS = new String(newCurArray);
if(!visited.contains(tempS)){
q.offer(tempS);
visited.add(tempS);
}
}
}
step++;
}
return -1;
}
public LinkedHashMap<Integer,LinkedList<Integer>> getNeighborIndex(int m,int n){
//数组的长度
int len = m*n;
LinkedHashMap<Integer,LinkedList<Integer>> neighbor = new LinkedHashMap<>();
//获取当前索引的上下左右的索引
for(int i=0;i<len;i++){
LinkedList<Integer> index = new LinkedList<>();
int otherIndex = i;
//上索引
if((otherIndex-n)>=0)
index.add(otherIndex-n);
//下索引
if((otherIndex+n)<len)
index.add(otherIndex+n);
//左索引 最左边为元素无左索引
if((otherIndex-1)>=0&&otherIndex%n!=0)
index.add(otherIndex-1);
//右索引 最右边为元素无右索引
if((otherIndex+1)<len&&((otherIndex+1)%n)!=0)
index.add(otherIndex+1);
neighbor.put(i,index);
}
return neighbor;
}
}