# 127. Word Ladder

Given two words (_beginWord_ and _endWord_), and a dictionary's word list, find the length of shortest transformation sequence from _beginWord_ to _endWord_, such that:

1. Only one letter can be changed at a time.
2. Each transformed word must exist in the word list. Note that _beginWord_ is _not_ a transformed word.

**Note:**

* Return 0 if there is no such transformation sequence.
* All words have the same length.
* All words contain only lowercase alphabetic characters.
* You may assume no duplicates in the word list.
* You may assume _beginWord_ and _endWord_ are non-empty and are not the same.

**Example 1:**

```
Input:
beginWord = "hit",
endWord = "cog",
wordList = ["hot","dot","dog","lot","log","cog"]

Output: 5

Explanation: As one shortest transformation is "hit" -> "hot" -> "dot" -> "dog" -> "cog",
return its length 5.
```

**Example 2:**

```
Input:
beginWord = "hit"
endWord = "cog"
wordList = ["hot","dot","dog","lot","log"]

Output: 0

Explanation: The endWord "cog" is not in wordList, therefore no possible transformation.
```

```cpp
// Single-End BFS
int ladderLength(string beginWord, string endWord, vector<string>& wordList) { // time: O(n * str_len); space: O(n * str_len)
    unordered_set<string> words(wordList.begin(), wordList.end());
    queue<string> q({beginWord});
    int res = 1;
    while (!q.empty()) {
        for (int k = q.size() - 1; k >= 0; --k) {
            string word = q.front(); q.pop();
            if (word == endWord) return res;
            for (int i = 0; i < word.length(); ++i) {
                string newWord = word;
                for (char ch = 'a'; ch <= 'z'; ++ch) {
                    newWord[i] = ch;
                    if (words.count(newWord) && newWord != word) {
                        q.push(newWord);
                        words.erase(newWord); // avoid visiting it twice
                    }
                }
            }
        }
        ++res;
    }
    return 0; // not found
}
```

```cpp
// Double-End BFS
int ladderLength(string beginWord, string endWord, vector<string>& wordList) { // time: O(n * str_len); space: O(n * str_len)
    unordered_set<string> dict(wordList.begin(), wordList.end());
    if (!dict.count(endWord)) return 0;
    unordered_set<string> q1({beginWord}), q2({endWord});
    int res = 0;
    while (!q1.empty() && !q2.empty()) {
        ++res;
        if (q1.size() > q2.size()) swap(q1, q2);
        unordered_set<string> tmp;
        for (const string& word : q1) {
            for (int i = 0; i < word.length(); ++i) {
                string newWord = word;
                for (char ch = 'a'; ch <= 'z'; ++ch) {
                    newWord[i] = ch;
                    if (q2.count(newWord)) return res + 1;
                    if (!dict.count(newWord)) continue;
                    dict.erase(newWord); // avoid visiting it twice
                    tmp.insert(newWord);
                }
            }
        }
        swap(q1, tmp);
    }
    return 0;
}
```
