leetcode:127. 单词接龙
题目
字典 wordList 中从单词 beginWord 和 endWord 的 转换序列 是一个按下述规格形成的序列 beginWord -> s1 -> s2 -> ... -> sk:
- 每一对相邻的单词只差一个字母。
- 对于
1 <= i <= k时,每个si都在wordList中。注意,beginWord不需要在wordList中。 sk == endWord
给你两个单词 beginWord 和 endWord 和一个字典 wordList ,返回 从 beginWord 到 endWord 的 最短转换序列 中的 单词数目 。如果不存在这样的转换序列,返回 0 。
示例:
输入:beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log","cog"]输出:5解释:一个最短转换序列是 "hit" -> "hot" -> "dot" -> "dog" -> "cog", 返回它的长度 5。
输入:beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log"]输出:0解释:endWord "cog" 不在字典中,所以无法进行转换。
解答 & 代码
层序遍历
class Solution {public:int ladderLength(string beginWord, string endWord, vector<string>& wordList) {// 将所有单词存储到哈希表,以便能在 O(1) 时间复杂度内判断一个单词是否存在 wordList 中unordered_set<string> wordsDict(wordList.begin(), wordList.end());// 如果 endWord 不在 wordList,肯定不存在转换序列,直接返回 0if(wordsDict.find(endWord) == wordsDict.end())return 0;queue<string> wordQ; // 队列,存储层序遍历的节点(单词)wordQ.push(beginWord);unordered_set<string> visited; // 哈希表,存储已访问过的单词visited.insert(beginWord);int depth = 1; // 当前序列的单词数// 层序遍历while(!wordQ.empty()){int levelCnt = wordQ.size();for(int i = 0; i < levelCnt; ++i){string curWord = wordQ.front();wordQ.pop();// 对于当前单词的每一位,依次改为 26 个字母for(int j = 0; j < curWord.size(); ++j){char originCh = curWord[j];for(int k = 0; k < 26; ++k){curWord[j] = 'a' + k;// 如果修改后的单词没被访问过,且存在 wordList 中,则存入队列(相当于当前单词的孩子节点)if(visited.find(curWord) == visited.end() &&wordsDict.find(curWord) != wordsDict.end()){// 如果修改后的单词就是 endWord,直接返回if(curWord == endWord)return depth + 1;else{wordQ.push(curWord);visited.insert(curWord);}}}curWord[j] = originCh; // 撤销对当前位的修改,去修改下一位字符}}++depth;}return 0;}};
复杂度分析:设字典 wordList 中包含 n 个单词,设单词长度 m
- 时间复杂度 O(nm26):访问每个单词一次,对于每个单词,遍历其每一位,分别修改为 26 个字母,看修改后的字符是否存在字典中且未被访问过
- 空间复杂度 O(nm):
- 哈希表 wordsDict 存储所有单词,每个单词长为 m
- 队列 wordQ 存储 BFS 遍历的节点(单词),存储的单数 O(n),每个单词长为 m
- 哈希表 visited 存储访问过的单词,最多 n 个,每个单词长为 m
执行结果:
执行结果:通过执行用时:164 ms, 在所有 C++ 提交中击败了 39.14% 的用户内存消耗:14.8 MB, 在所有 C++ 提交中击败了 61.99% 的用户
