這是最基本的建圖、BFS遍歷的方式,可AC,但時間很差。
時間複雜度:
class Solution {
public:
unordered_map<string,vector<string>> graph;
unordered_set<string> vis;
queue<string> q;
int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
create(beginWord,graph,wordList);
q.push(beginWord);
vis.insert(beginWord);
int step = 1;
while(!q.empty()){
int size = q.size();
while(size--){
string x = q.front();q.pop();
for(string y:graph[x]){
if(!vis.count(y)) {
if(y==endWord){
return step+1;
}
q.push(y);
vis.insert(y);
}
}
}
step ++;
}
return 0;
}
void create(string &beginWord,unordered_map<string,vector<string>> &graph,vector<string>& wordList){
wordList.push_back(beginWord);
for(int i=0;i<wordList.size();i++) {
for(int j=i+1;j<wordList.size();j++){
if(isConnect(wordList[i],wordList[j])){
graph[wordList[i]].push_back(wordList[j]);
graph[wordList[j]].push_back(wordList[i]);
}
}
}
}
bool isConnect(string &x,string &y){
int res = 0;
for(int i=0;i<x.size();i++){
if(x[i]!=y[i]){
res++;
}
}
return res==1;
}
};
說個小插曲(我就被這個坑了 ):
下面的函數的參數必須傳遞引用,否則傳值拷貝的話,立馬TLE !!!。
bool isConnect(string &x,string &y){
int res = 0;
for(int i=0;i<x.size();i++){
if(x[i]!=y[i]){
res++;
}
}
return res==1;
}
上面這種建圖方式,實際上對每一個字符串是去遍歷字符串序列去找到它的t拓展點的。
整體時間複雜度
如果換一種思路的話,對於每一個字符串,它可能的拓展的點是有限的,就是每個位置都去替換一個不同字符,然後已有的wordLIst
裏面有沒有它。
當然爲了更高效的查詢,我們用unordered_set<string>
去存儲已有的字符串。
這裏介紹一個函數,能把vector
轉換爲set
vector<string> v;
set<string> s(v.begin(),v.end());
這個時間複雜度:,運行時間減少了一個數量級
class Solution {
public:
int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
unordered_set<string> wordSet(wordList.begin(),wordList.end());
if(!wordSet.count(endWord)){
return 0;
}
unordered_set<string> vis;
queue<string> q;
q.push(beginWord);
vis.insert(beginWord);
int step = 1;
while(!q.empty()){
int size = q.size();
while(size--){
string a = q.front();
q.pop();
//時間複雜度 26*wordLen
for(int i=0;i<a.size();i++){
char origin = a[i];
for(char c = 'a';c<='z';c++){
if(c==origin){
continue;
}
a[i] = c;
if(wordSet.count(a)){
if(a==endWord){
return step+1;
}
q.push(a);
vis.insert(a);
}
}
a[i] =origin;
}
}
step++;
}
return 0;
}
};
雙向BFS
對於給定了起點和終點的搜索,使用雙向BFS可能更加方便。
雙向BFS的基本搜索框架和之前的差不多,只不過現在有兩個隊列, 兩個標記數組,
搜索的終點也變成了:兩個標記數組都搜到了某一個點。
class Solution {
public:
int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
unordered_set<string> wordSet(wordList.begin(),wordList.end());
if(!wordSet.count(endWord)){
return 0;
}
unordered_map<string,int> pre,post,vis[2] = {pre,post};
queue<pair<string,int>> queFront,queBack,q[2] = {queFront,queBack};
q[0].push(make_pair(beginWord,1));
q[1].push(make_pair(endWord,1));
vis[0][beginWord] = 1;
vis[1][endWord] = 1;
while(!q[0].empty() || !q[1].empty()){
bool flag = q[0].size()<=q[1].size() && q[0].size()!=0 ?0:1;
int size = q[flag].size();
while(size--){
pair<string,int> x = q[flag].front();
q[flag].pop();
for(int i=0;i<x.first.size();i++){
char origin = (x.first)[i];
for(char c='a';c<='z';c++){
if(origin==c){
continue;
}
x.first[i] = c;
if(wordSet.count(x.first) && !vis[flag].count(x.first) ){
if(vis[!flag].count(x.first)){
return x.second+vis[!flag][x.first];
}
q[flag].push(make_pair(x.first,x.second+1));
vis[flag][x.first] = x.second+1 ;
}
x.first[i] = origin;
}
}
}
}
return 0;
}
};