时间轴
时间轴
2025-11-24
init
BFS
题目:
BFS 暴力枚举,这是我最先想出的方法,但是效率很低。
BFS 暴力枚举
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263 | using std::string;using std::unordered_set;using std::vector;using std::queue;class Solution { private: bool is_neighbor(string word, string possible_neighbor) { int diff_cnt = 0, n = word.size(); if (possible_neighbor.size() != n) { return false; } for (int i = 0; i < n; i++) { if (word[i] != possible_neighbor[i]) { diff_cnt++; } if (diff_cnt > 1) { return false; } } return true; } public: int ladderLength(string beginWord, string endWord, vector<string> &wordList) { int i, n, level = 1; queue<string> que; unordered_set<string> visited; string curr_word; que.push(beginWord); visited.insert(beginWord); while (!que.empty()) { n = que.size(); for (i = 0; i < n; i++) { curr_word = que.front(); que.pop(); if (curr_word == endWord) { return level + 1; } for (auto &possible_neighbor : wordList) { if (!visited.count(possible_neighbor) && is_neighbor(curr_word, possible_neighbor)) { que.push(possible_neighbor); visited.insert(possible_neighbor); } } } level++; } return 0; }}; |
BFS+虚拟节点优化建图
官方题解:我们先给每一个单词标号,即给每个单词分配一个 id。创建一个由单词 word 到 id 对应的映射 wordId,并将 beginWord 与 wordList 中所有的单词都加入这个映射中。之后我们检查 endWord 是否在该映射内,若不存在,则输入无解。我们可以使用哈希表实现上面的映射关系。
然后我们需要建图,依据朴素的思路,我们可以枚举每一对单词的组合,判断它们是否恰好相差一个字符,以判断这两个单词对应的节点是否能够相连。但是这样效率太低,我们可以优化建图。
具体地,我们可以创建虚拟节点。对于单词 hit,我们创建三个虚拟节点 it、ht、hi*,并让 hit 向这三个虚拟节点分别连一条边即可。如果一个单词能够转化为 hit,那么该单词必然会连接到这三个虚拟节点之一。对于每一个单词,我们枚举它连接到的虚拟节点,把该单词对应的 id 与这些虚拟节点对应的 id 相连即可。
最后我们将起点加入队列开始广度优先搜索,当搜索到终点时,我们就找到了最短路径的长度。注意因为添加了虚拟节点,所以我们得到的距离为实际最短路径长度的两倍。同时我们并未计算起点对答案的贡献,所以我们应当返回距离的一半再加一的结果。
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758 | class Solution {public: unordered_map<string, int> wordId; vector<vector<int>> edge; int nodeNum = 0; void addWord(string& word) { if (!wordId.count(word)) { wordId[word] = nodeNum++; edge.emplace_back(); } } void addEdge(string& word) { addWord(word); int id1 = wordId[word]; for (char& it : word) { char tmp = it; it = '*'; addWord(word); int id2 = wordId[word]; edge[id1].push_back(id2); edge[id2].push_back(id1); it = tmp; } } int ladderLength(string beginWord, string endWord, vector<string>& wordList) { for (string& word : wordList) { addEdge(word); } addEdge(beginWord); if (!wordId.count(endWord)) { return 0; } vector<int> dis(nodeNum, INT_MAX); int beginId = wordId[beginWord], endId = wordId[endWord]; dis[beginId] = 0; queue<int> que; que.push(beginId); while (!que.empty()) { int x = que.front(); que.pop(); if (x == endId) { return dis[endId] / 2 + 1; } for (int& it : edge[x]) { if (dis[it] == INT_MAX) { dis[it] = dis[x] + 1; que.push(it); } } } return 0; }}; |
