Leetcode 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] 的排列.
题解
bfs
棋盘哈希,我们用每个各自拼接成的字符串表示一个棋盘的状态;为了快速找到0的位置,我们需要记录其位置;bfs找最短步数。详细过程见代码
代码
#define m 2
#define n 3
class Chess{
public:
int zeroX;
int zeroY;
vector<vector<int>> board;
Chess(int zeroX,int zeroY,vector<vector<int>>& board){
this->zeroX = zeroX;
this->zeroY = zeroY;
this->board = vector<vector<int>>(m,vector<int>(n,0));
for(int i=0; i<m; i++){
for(int j=0; j<n; j++){
this->board[i][j] = board[i][j];
}
}
}
};
class Solution {
public:
vector<vector<int>> target = vector<vector<int>>(m,vector<int>(n,0)); //目标棋盘
bool isTarget(vector<vector<int>>& board){ //判断当前棋盘是否为目标棋盘
for(int i=0; i<m; i++){
for(int j=0; j<n; j++){
if(board[i][j] != target[i][j])
return false;
}
}
return true;
}
string chessToStr(vector<vector<int>>& board){ //将棋盘状态用字符串表示
string now;
for(int i=0; i<m; i++){
for(int j=0; j<n; j++)
now += to_string(board[i][j]);
}
return now;
}
int slidingPuzzle(vector<vector<int>>& board) {
int cnt = 1;
int zeroX,zeroY;
string now;
for(int i=0; i<m; i++){ //构造目标棋盘的同时,将初始状态转为字符串
for(int j=0; j<n; j++){
target[i][j] = cnt++;
if(board[i][j] == 0){
zeroX = i;
zeroY = j;
}
now += to_string(board[i][j]);
}
}
unordered_set<string> used; //已有状态
used.insert(now);
target[m-1][n-1] = 0;
int dir[4][2] = {
{-1,0},{0,1},{1,0},{0,-1}
};
queue<Chess> q;
q.push(Chess(zeroX,zeroY,board));
int ans = -1,size;
while(!q.empty()){
size = q.size();
ans++;
while(size--){
Chess now = q.front();
vector<vector<int>> chess = now.board;
if(isTarget(chess)) return ans;
q.pop();
for(int i=0; i<4; i++){
if(now.zeroX+dir[i][0]>=0 && now.zeroX+dir[i][0]<m
&& now.zeroY+dir[i][1]>=0 && now.zeroY+dir[i][1]<n){
chess[now.zeroX][now.zeroY] = chess[now.zeroX+dir[i][0]][now.zeroY+dir[i][1]];
chess[now.zeroX+dir[i][0]][now.zeroY+dir[i][1]] = 0;
string nowChessStr = chessToStr(chess);
if(used.find(nowChessStr) == used.end()){
q.push(Chess(now.zeroX+dir[i][0],now.zeroY+dir[i][1],chess));
used.insert(nowChessStr);
}
chess[now.zeroX+dir[i][0]][now.zeroY+dir[i][1]] = chess[now.zeroX][now.zeroY];
chess[now.zeroX][now.zeroY] = 0;
}
}
}
}
return -1;
}
};
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/sliding-puzzle
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。