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

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

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


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

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

# C++
## 思路一
``` 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);   
    }
};
```

## 思路二
``` C++
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);   
    }
};
```

## 思路三
``` C++
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;
    }
};
```

