题目描述:
在一个 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
解释:没有办法完成谜板
题源:https://leetcode-cn.com/problems/sliding-puzzle/
题解:https://michael.blog.csdn.net/article/details/104118648
利用字符串压缩状态,用map作hash,看是否有重复。
学点:
- stoi() 对单个字符不适用,报错,对整串字符符合。( 区别于atoi(string.c_str()) )
- string类型,如果在末尾加一个字符,可以用push_back(),删除末尾一个字符可以用:pop_back()
- 在函数类型后加“&“,表示引用,也就是在函数中值变化,对应主代码中变量值也随之改变。
- string拆单个字符出来,比较是用单引号‘’,而不是双引号“”
代码:
class Solution { public: string vtos(vector<vector<int>> k) { string s; for(int i=0;i<2;i++) for(int j=0;j<3;j++) s.push_back(k[i][j]+'0'); // 或者 s=s+to_string(b[i][j]); return s; } void stov(string &s,int &x0,int &y0,vector<vector<int>>& k) { for(int i=0;i<2;i++) for(int j=0;j<3;j++) { k[i][j]=s[i*3+j]-'0'; if( k[i][j]==0 ) { x0=i; y0=j; } // 正确:if (s[i*3+j=='0') 错误:if(s[i*3+j]=="0) } return; } int slidingPuzzle(vector<vector<int>>& board) { int d[4][2]={{1,0},{0,1},{-1,0},{0,-1}}; map<string,int> mp; bool flag=0; queue<string> Q; string s=vtos(board); Q.push(s); mp[s]=0; while(!Q.empty()) { string p=Q.front(); Q.pop(); int x0,y0; stov(p,x0,y0,board); //得到0点坐标,并且形成矩阵 for(int i=0;i<4;i++) { int x=x0+d[i][0]; int y=y0+d[i][1]; if(!((x>=0 && x<2) && (y>=0 && y<3)) ) continue; swap(board[x0][y0],board[x][y]); string s; for(int ii=0;ii<2;ii++) for(int jj=0;jj<3;jj++) s=s+to_string(board[ii][jj]); // 或 s.push_back(board[ii][jj]+'0'); if(mp.find(s)==mp.end()) { mp[s]=mp[p]+1; Q.push(s); } if(s=="123450") {flag=1; break;} swap(board[x0][y0],board[x][y]); } if(flag) break; } if(flag) return mp["123450"]; else return -1; } };