转盘锁有四位,每位10个数字,每次只能转一位,而且转的过程中不能出现deadends中的情况,求出最后转几步才能的出target。
一串字符串往上往下拨一位会有8种情况,相当于一个节点有8个邻接节点,在这么一个图中,只有一个终点,而且有的节点是不能用的,题目最后转换成BFS求最短路径。
而DFS求最短路径需要遍历整张图之后,保存所有的结果在选出最优的,在时间上已经败了。
求最短路径的时候,要避免走重复的路,所以要记录已经走过的路,基于这一点,可以把那些deadends条件的节点当成已经走过的路,省的另开空间去判断。
//608 ms, 33.9 MB
class Solution {
public:
//向上拨一位,string可以直接通过下标访问已有元素
string getUp(string source, int UpBit){
string res = source;
if(res[UpBit]=='9')
res[UpBit] = '0';
else
res[UpBit]+=1;
return res;
}
//向下拨一位
string getDown(string source, int DownBit){
string res = source;
if(res[DownBit]=='0')
res[DownBit] = '9';
else
res[DownBit]-=1;
return res;
}
int openLock(vector<string>& deadends, string target) {
queue<string> q;
unordered_set<string> visited;
int step = 0;
//将dead情况视为visited
for(int i = 0;i < deadends.size(); i ++){
visited.insert(deadends[i]);
}
//一种极端的情况是,起始状态就是dead
if(visited.count("0000"))
return -1;
q.push("0000");
visited.insert("0000");
while(!q.empty()){
int sz = q.size();
for(int i=0;i<sz;i++){
string tmp = q.front();
q.pop();
if(tmp==target){
return step;
}
//一个节点有八个邻接节点
for(int j=0;j<4;j++){
string tmpUp = getUp(tmp, j);
if(!visited.count(tmpUp)){
q.push(tmpUp);
visited.insert(tmpUp);
}
string tmpDown = getDown(tmp, j);
if(!visited.count(tmpDown)){
q.push(tmpDown);
visited.insert(tmpDown);
}
}
}
step++;
}
return -1;
}
};
unordered_set中判断是否存在某个元素,可以用count()函数,
若不存在函数返回0,存在返回1
#include<cstdio>
#include<iostream>
#include<unordered_set>
using namespace std;
main(){
unordered_set<int> us;
us.insert(1);
us.insert(2);
us.insert(3);
cout<<us.count(6)<<endl;
return 0;
}
这一部分是把string转换成char* 或 char[] 来处理的前置
c语言中没有string类型,可以通过string类对象的成员函数c_str()把string对象转换成c中的字符串样式。
const char *c_str();
c_str()函数返回一个指向正规C字符串的指针常量, 内容与本string串相同.
注意:一定要使用strcpy()函数 等来操作c_str()返回的指针
不要这样:
char* c;
string s="1234";
//c最后指向的内容是垃圾,因为s对象被析构,其内容被处理
//同时,编译器也将报错——将一个const char 赋与一个char
c = s.c_str();
应该这样:
char c[20];
string s="1234";
strcpy(c,s.c_str());
这样才不会出错,c_str()返回的是一个const指针,不能对其进行操作
再举个例子
c_str() 以 char* 形式传回 string 内含字符串
如果一个函数要求char*参数,可以使用c_str()方法:
string s = "Hello World!";
printf("%s", s.c_str()); //输出 "Hello World!"
传统的BFS框架都是从起点开始往四周扩散,遇到终点停止。而双向BFS优化的思路是,起点和终点同时向四周扩散,当两个方向有交集的时候停止。
这个思路的前提是知道终点。起点、终点同时保留一个扩散的集合,当两个集合有交集终止。
区别在于传统的要走一棵树,双向走半棵树就会得到,但是从O(N)和O(N/2)的角度看时间复杂度是一样的。按下不表。