127. Word Ladder

1. Description

A transformation sequence from word beginWord to word endWord using a dictionary wordList is a sequence of words beginWord -> s1 -> s2 -> … -> sk such that:

  • Every adjacent pair of words differs by a single letter.
  • Every si for 1 <= i <= k is in wordList. Note that beginWord does not need to be in wordList. sk == endWord

Given two words, beginWord and endWord, and a dictionary wordList, return the number of words in the shortest transformation sequence from beginWord to endWord, or 0 if no such sequence exists.

2. Example

Example 1:
Input: beginWord = “hit”, endWord = “cog”, wordList = [“hot”,“dot”,“dog”,“lot”,“log”,“cog”]
Output: 5
Explanation: One shortest transformation sequence is “hit” -> “hot” -> “dot” -> “dog” -> cog", which is 5 words long.

Example 2:
Input: beginWord = “hit”, endWord = “cog”, wordList = [“hot”,“dot”,“dog”,“lot”,“log”]
Output: 0
Explanation: The endWord “cog” is not in wordList, therefore there is no valid transformation sequence.

3. Constraints

  • 1 <= beginWord.length <= 10
  • endWord.length == beginWord.length
  • 1 <= wordList.length <= 5000
  • wordList[i].length == beginWord.length
  • beginWord, endWord, and wordList[i] consist of lowercase English letters.
  • beginWord != endWord
  • All the words in wordList are unique.

4. Solutions

m = wordList[i].size(), n = wordList.size()
Time complexity: O($m^2$n)
Space complexity: O($m^2$n)

class Solution {
public:
    int ladderLength(
        const string &beginWord,
        const string &endWord,
        const vector<string> &wordList) {
        unordered_map<string, unordered_set<string>> fake_neighbors;
        bool have_end = false;
        for (const auto &word : wordList) {
            if (word == endWord) {
                have_end = true;
            }

            string fake_neightbor = word;
            for (int i = 0; i < word.size(); ++i) {
                char letter = fake_neightbor[i];
                fake_neightbor[i] = '*';
                fake_neighbors[fake_neightbor].insert(word);
                fake_neightbor[i] = letter;
            }
        }

        if (!have_end) {
            return 0;
        }

        int path = 1;
        queue<string> current_words({beginWord}), neighbor_words;
        for (; !current_words.empty(); ++path) {
            while (!current_words.empty()) {
                auto current_word = current_words.front();
                current_words.pop();

                string fake_neightbor = current_word;
                for (int i = 0; i < current_word.size(); ++i) {
                    char letter = fake_neightbor[i];
                    fake_neightbor[i] = '*';
                    fake_neighbors[fake_neightbor].erase(current_word);
                    for (auto word : fake_neighbors[fake_neightbor]) {
                        if (word == endWord) {
                            return path + 1;
                        }

                        neighbor_words.push(word);
                    }

                    fake_neighbors.erase(fake_neightbor);
                    fake_neightbor[i] = letter;
                }
            }

            swap(current_words, neighbor_words);
        }

        return 0;
    }
};
comments powered by Disqus