[LeetCode]Word Ladder

解題思路:
雙向 寬度搜索
1,BFS的基本思想是爲了找到最短路徑,這裏爲了提高搜索效率,採用雙向搜索。
2,是從beginWord方向尋找next level,還是從endWord方向尋找next level,取決於哪個方向要找尋的點少
數據結構:
1,unordered_set : unusedWords, wordDict中所有未被visit的words
2,unordered_set : activeWords[startSet], 保存我們即將要用於搜索的words(beginWord 方向,或者endWord方向,取決於size)
3,unordered_set : activeWords[endSet], 與2中 unordered_set 對應的另一邊words
如果BFS擴展路徑的時候(從activeWords[startSet])到達了一個存在於(activeWords[endSet])的word,那麼我們就找到了一個條最短路徑
4,unordered_set :  activeWords[nextSet],保存BFS從activeWords[StartSet] 擴展出的節點word
5,對BFS的每一步,我們動態的決定應該從哪個方向擴展,主要取決於哪個方向的nodes更少。這樣做可以降低搜索複雜度。

在BFS階段,遍歷startSet裏面的每一個word,先看endSet裏有沒有next Level的單詞,如果有,則找到一條最短路徑,直接返回。否則,再在unusedSet裏面找next Level的節點,如果有,加入nextSet,並且從unusedWords中刪除 

// 860 ms
class Solution {
public:
    int ladderLength(string beginWord, string endWord, unordered_set<string>& wordDict) {
        int bLen = beginWord.length();
        int eLen = endWord.length();
        int size = wordDict.size();
        if (bLen != eLen || bLen == 0 || size == 0) return 0;

        unordered_set<string> unusedWords = wordDict; // words that never visited before
        unordered_set<string> activeWords[3];
        int startSet = 0;
        int endSet = 1;
        int nextSet = 2;
        int depth = 2;

        activeWords[startSet].insert(beginWord);
        activeWords[endSet].insert(endWord);
        unusedWords.erase(beginWord);
        unusedWords.erase(endWord);
        while(!activeWords[startSet].empty()){
            for (auto it : activeWords[startSet]){
                for (auto itend : activeWords[endSet]){
                    if (match(it, itend)){
                        return depth;
                    }
                }

                vector<string> temp;
                for (auto itun : unusedWords){
                    if (match(it, itun)){
                        activeWords[nextSet].insert(itun);
                        temp.push_back(itun);
                        //這裏不能直接用下面這句,因爲你迭代器是 unusedWords的,把它的元素刪除,迭代器就被玩壞了
                        //unusedWords.erase(itun);
                    }
                }
                for (auto istr : temp){
                    unusedWords.erase(istr);
                }

            }
            depth++;
            swap(startSet, nextSet);
            if (activeWords[startSet].size() > activeWords[endSet].size()) {
                swap(startSet, endSet);
            }
            activeWords[nextSet].clear();
        }
        return 0;
    }

    bool match(string wordA, string wordB){
        if (wordA.length() != wordB.length()) return false;
        int diff = 0;
        for (int i = 0; i < wordA.length(); ++i){
            if (wordA[i] == wordB[i]) continue;

            diff++;
            if (diff > 1){
                return false;
            }
        }
        if (diff == 1) return true;
        return false;
    }
};

上述算法860ms,改變一下match算法,時間減少的68ms,原因在於
第一種算法,每兩個word都要進行一次匹配,O(m*n), 每次匹配要判斷 word的長度個次數,所以總時間複雜度時O(m*n*k)
第二種算法,由於unordered_set的查找時間複雜度爲O(1), 所以實際的時間複雜度是隻跟word的長度有關係,即O(n), 26個字母的替換,常量啦 
        for (auto it : activeWords[startSet]){
                char temp, i;
                for(int i = 0; i < it.length(); ++i){
                    temp = it[i];
                    for(char j = 'a'; j < 'z'; ++j){
                        if (temp == j) continue;
                        it[i] = j;
                        if (activeWords[endSet].count(it) > 0){
                            return depth;
                        }else if (unusedWords.count(it) > 0){
                            activeWords[nextSet].insert(it);
                            unusedWords.erase(it);
                        }
                    }
                    it[i] = temp;
                }
            }




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章