LeetCode/solutions/127. Word Ladder.md
2019-07-08 23:25:30 +08:00

4.9 KiB
Raw Blame History

127. Word Ladder

思路

词句阶梯: 给了我们一个单词字典,里面有一系列很相似的单词,然后给了一个起始单词和一个结束单词,每次变换只能改变一个单词,并且中间过程的单词都必须是单词字典中的单词,让我们求出最短的变化序列的长度。
要求最短路径长度首先应该想到BFS。类似迷宫里面的最短路求法迷宫每个点有上下左右四个方向可以走而这里有26个字母就是二十六个方向可以走本质上没有区别。

另外由于需要频繁判断某个单词是否在字典中所以我们用hashSet记录词典代码中的wordSet)以快速进行判断。

思路一

采用递归的BFS。首先我们用一个词语数组beginWords来记录开始的词语,初始化为一个元素beginWord,此外类似走迷宫的题目我们还需要一个visited来记录当前词语是否被访问过这里我们用hashSet来定义visited。递归出口是beginWords为空。

思路二、思路一改进

仔细分析我们可以发现了个hashSetwordSetvisited其实在功能上是有冗余的: 如果我们每访问一次wordSet里的词然后就把它从wordSet中去掉,这样不就不需要visited了吗?亲测会比思路一快很多。

思路三

思路二的非递归版本。此时就不需要beginWords了而需要一个队列。

C++

思路一

class Solution {
private:
    int BFS(vector<string>beginWords, unordered_set<string>&wordSet, 
            unordered_set<string>&visited, string &endWord){
        vector<string>next_beginWords;
        string word;
        for(int i = 0; i < beginWords.size(); i++){
            for(int j = 0; j < endWord.size(); j++){
                word = beginWords[i];
                if(word == endWord) return 1;
                for(char k = 'a'; k <= 'z'; k++){
                    word[j] = k;
                    if(!wordSet.count(word) || visited.count(word)) continue;
                    
                    visited.insert(word);
                    next_beginWords.push_back(word);
                }
            }
        }
        if(next_beginWords.empty()) return 0; // 递归出口
        return BFS(next_beginWords, wordSet, visited, endWord) + 1;
    }
    
public:
    int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
        unordered_set<string>wordSet(wordList.begin(), wordList.end());
        unordered_set<string>visited{beginWord};
        if(wordSet.count(endWord) != 1) return 0;
        vector<string>beginWords{beginWord};
        return BFS(beginWords, wordSet, visited, endWord);   
    }
};

思路二

class Solution {
private:
    int BFS(vector<string>beginWords, unordered_set<string>&wordSet, string &endWord){
        vector<string>next_beginWords;
        string word;
        for(int i = 0; i < beginWords.size(); i++){
            for(int j = 0; j < endWord.size(); j++){
                word = beginWords[i];
                if(word == endWord) return 1;
                char tmp_c = word[j];
                for(char k = 'a'; k <= 'z'; k++){
                    word[j] = k;
                    // tmp_c == k即新旧单词相同
                    if(!wordSet.count(word) || tmp_c == k) continue;

                    wordSet.erase(word);
                    next_beginWords.push_back(word);
                }
            }
        }
        if(next_beginWords.empty()) return 0; // 递归出口
        return BFS(next_beginWords, wordSet, endWord) + 1;
    }
    
public:
    int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
        unordered_set<string>wordSet(wordList.begin(), wordList.end());
        if(wordSet.count(endWord) != 1) return 0;
        vector<string>beginWords{beginWord};
        return BFS(beginWords, wordSet, endWord);   
    }
};

思路三

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;
        queue<string> q;
        q.push(beginWord);
        int res = 0;
        while (!q.empty()) {
            for (int k = q.size(); k > 0; --k) {
                string word = q.front(); q.pop();
                if (word == endWord) return res + 1;
                for (int i = 0; i < word.size(); ++i) {
                    string newWord = word;
                    for (char k = 'a'; k <= 'z'; ++k) {
                        newWord[i] = k;
                        if (wordSet.count(newWord) && newWord != word) {
                            q.push(newWord);
                            wordSet.erase(newWord);
                        }   
                    }
                }
            }
            ++res;
        }
        return 0;
    }
};