leetcode:127. 单词接龙

题目

字典 wordList 中从单词 beginWordendWord转换序列 是一个按下述规格形成的序列 beginWord -> s1 -> s2 -> ... -> sk

  • 每一对相邻的单词只差一个字母。
  • 对于 1 <= i <= k 时,每个 si 都在 wordList 中。注意, beginWord 不需要在 wordList 中。
  • sk == endWord

给你两个单词 beginWordendWord 和一个字典 wordList ,返回 从 beginWordendWord最短转换序列 中的 单词数目 。如果不存在这样的转换序列,返回 0

示例:

  1. 输入:beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log","cog"]
  2. 输出:5
  3. 解释:一个最短转换序列是 "hit" -> "hot" -> "dot" -> "dog" -> "cog", 返回它的长度 5
  1. 输入:beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log"]
  2. 输出:0
  3. 解释:endWord "cog" 不在字典中,所以无法进行转换。

解答 & 代码

层序遍历

  1. class Solution {
  2. public:
  3. int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
  4. // 将所有单词存储到哈希表,以便能在 O(1) 时间复杂度内判断一个单词是否存在 wordList 中
  5. unordered_set<string> wordsDict(wordList.begin(), wordList.end());
  6. // 如果 endWord 不在 wordList,肯定不存在转换序列,直接返回 0
  7. if(wordsDict.find(endWord) == wordsDict.end())
  8. return 0;
  9. queue<string> wordQ; // 队列,存储层序遍历的节点(单词)
  10. wordQ.push(beginWord);
  11. unordered_set<string> visited; // 哈希表,存储已访问过的单词
  12. visited.insert(beginWord);
  13. int depth = 1; // 当前序列的单词数
  14. // 层序遍历
  15. while(!wordQ.empty())
  16. {
  17. int levelCnt = wordQ.size();
  18. for(int i = 0; i < levelCnt; ++i)
  19. {
  20. string curWord = wordQ.front();
  21. wordQ.pop();
  22. // 对于当前单词的每一位,依次改为 26 个字母
  23. for(int j = 0; j < curWord.size(); ++j)
  24. {
  25. char originCh = curWord[j];
  26. for(int k = 0; k < 26; ++k)
  27. {
  28. curWord[j] = 'a' + k;
  29. // 如果修改后的单词没被访问过,且存在 wordList 中,则存入队列(相当于当前单词的孩子节点)
  30. if(visited.find(curWord) == visited.end() &&
  31. wordsDict.find(curWord) != wordsDict.end())
  32. {
  33. // 如果修改后的单词就是 endWord,直接返回
  34. if(curWord == endWord)
  35. return depth + 1;
  36. else
  37. {
  38. wordQ.push(curWord);
  39. visited.insert(curWord);
  40. }
  41. }
  42. }
  43. curWord[j] = originCh; // 撤销对当前位的修改,去修改下一位字符
  44. }
  45. }
  46. ++depth;
  47. }
  48. return 0;
  49. }
  50. };

复杂度分析:设字典 wordList 中包含 n 个单词,设单词长度 m

  • 时间复杂度 O(nm26):访问每个单词一次,对于每个单词,遍历其每一位,分别修改为 26 个字母,看修改后的字符是否存在字典中且未被访问过
  • 空间复杂度 O(nm):
    • 哈希表 wordsDict 存储所有单词,每个单词长为 m
    • 队列 wordQ 存储 BFS 遍历的节点(单词),存储的单数 O(n),每个单词长为 m
    • 哈希表 visited 存储访问过的单词,最多 n 个,每个单词长为 m

执行结果:

  1. 执行结果:通过
  2. 执行用时:164 ms, 在所有 C++ 提交中击败了 39.14% 的用户
  3. 内存消耗:14.8 MB, 在所有 C++ 提交中击败了 61.99% 的用户