LeetCode 127. 單詞接龍(unordered_set的妙用、雙向BFS)

單詞接龍

這是最基本的建圖、BFS遍歷的方式,可AC,但時間很差。
時間複雜度:O(n2)O(n^2)

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拓展點的。
整體時間複雜度O(n2len(word))O(n^2*len(word))

如果換一種思路的話,對於每一個字符串,它可能的拓展的點是有限的,就是每個位置都去替換一個不同字符,然後已有的wordLIst裏面有沒有它。
當然爲了更高效的查詢,我們用unordered_set<string> 去存儲已有的字符串。
這裏介紹一個函數,能把vector轉換爲set

vector<string> v;
set<string> s(v.begin(),v.end());

這個時間複雜度:O(nlen(word))O(n*len(word)),運行時間減少了一個數量級

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;
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章