Word Ladder II -- leetcode
来源:互联网 发布:redis数据库有什么用 编辑:程序博客网 时间:2024/06/05 02:37
Given two words (start and end), and a dictionary, find all shortest transformation sequence(s) from start to end, such that:
- Only one letter can be changed at a time
- Each intermediate word must exist in the dictionary
For example,
Given:
start = "hit"
end = "cog"
dict = ["hot","dot","dog","lot","log"]
Return
[ ["hit","hot","dot","dog","cog"], ["hit","hot","lot","log","cog"] ]
Note:
- All words have the same length.
- All words contain only lowercase alphabetic characters.
基本思路:
要找出变化的最短路径,则需要进行一次广度优先搜索,以求得路径最小长度。
再进行一次深度优先搜索,以记录这些能达到目的地的路径。
从一个节点,找到它的邻接点时,通过将每位字符吕a-z逐一进行变化,然后在字典中查找是否存在。
在第一次广度优先搜索之时,记录下每个节点所在树的层次,即距离起始点的最小长度。
然后在深度优先搜索时,利用上面得到的信息。可以避免死循环,以及比淘汰比更短路径更长的路径。
因为每次找邻接点时,检查它是比本节点更上一层的接点。
深度优先搜索,开始与广度优先执行相反的方向。 即如果广度优先执行从start开始, 则深度从end开始。 即自底向上到顶。
因为达到层次1时,0层肯定就是start,无需再计算。 反之,从顶到底的话,因为底部不一定都是end。
而最好的方式,当是广度优先搜索,从end开始。 而深度则从start开始,这样的好处,是省去了最后路径的一个reverse操作。
下面 代码是BFS从start开始,故在最后路径,需要一个reverse操作。
在代码在 leetcode上实际执行时间为476ms。
class Solution {public: vector<vector<string>> findLadders(string start, string end, unordered_set<string> &dict) { vector<vector<string>> ans; vector<string> trace; unordered_map<string, int> visited; if (bfs(start, end, dict, visited)) dfs(start, end, visited, visited[end], trace, ans); return ans; } bool bfs(string start, string end, const unordered_set<string> &dict, unordered_map<string, int> &visited) { queue<string> q; q.push(start); int level = 0; visited[start] = level; bool found = false; while (!found && !q.empty()) { ++level; int count = q.size(); while (count--) { string word = q.front(); q.pop(); for (int i=0; i<word.size(); i++) { const char ch = word[i]; for (char j='a'; j<='z'; j++) { word[i] = j; if (dict.find(word) != dict.end() && visited.find(word) == visited.end()) { q.push(word); visited[word] = level; if (word == end) found = true; } } word[i] = ch; } } } return found; } void dfs(const string &start, string &end, const unordered_map<string, int> &levelmap, int level, vector<string> &path, vector<vector<string>> &ans) { auto iter = levelmap.find(end); if (iter == levelmap.end() || iter->second != level) return; if (level == 1) { ans.push_back(path); ans.back().push_back(end); ans.back().push_back(start); reverse(ans.back().begin(), ans.back().end()); return; } path.push_back(end); for (int i=0; i<end.size(); i++) { const char ch = end[i]; for (char j='a'; j<='z'; j++) { end[i] = j; dfs(start, end, levelmap, level-1, path, ans); } end[i] = ch; } path.pop_back(); }};
上面在BFS过程中,并未存储邻接点信息。即并未保持,树的父子关系。
在进行DFS过程中,邻接点仍需要进行重新计算。
偿试了一下,在BFS保存邻接点信息。每个结点保存了达到该结点的上一层的所有结点。
发现了BFS写起来要比上面复杂了。不再是那么单纯了: 那个visited,存入时间t和判断时间需要特殊考虑
虽然在visited上下了功夫,保证没有循环回路的产生;但无法避免同一层次结点之间的包含。
故在DFS搜索时,还是需要借助level递减这种方式,剔除,那些走了平行结点的路径。因为这些路径比最短路径要长。
此代码在leetcode上实际执行时间为1160ms。
大大的慢于上面的算法。
而且空间利用比上面更多。
看来此算法不可取。
class Solution {public: vector<vector<string>> findLadders(string start, string end, unordered_set<string> &dict) { vector<vector<string>> ans; unordered_map<string, unordered_set<string>> tree; vector<string> path; int level; if (bfs(start, end, dict, tree, level)) dfs(start, end, tree, path, level, ans); return ans; } bool bfs(string start, string end, const unordered_set<string> &dict, unordered_map<string, unordered_set<string>> &tree, int &level) { unordered_set<string> visited; queue<string> q; q.push(end); bool found = false; level = 0; while (!found && !q.empty()) { int count = q.size(); ++level; while (count--) { string word = q.front(); q.pop(); if (visited.find(word) != visited.end()) continue; visited.insert(word); const string parent = word; for (int i=0; i<word.size(); i++) { const char ch = word[i]; for (char j='a'; j<='z'; j++) { word[i] = j; if (dict.find(word) != dict.end() && visited.find(word) == visited.end()) { q.push(word); tree[word].insert(parent); if (word == start) found = true; } } word[i] = ch; } } } return found; } void dfs(string start, string end, unordered_map<string, unordered_set<string>> &tree, vector<string> &path, int level, vector<vector<string>> &ans) { path.push_back(start); if (start == end) { ans.push_back(path); } else if (level) { const auto &parents = tree[start]; for (auto p: parents) { dfs(p, end, tree, path, level-1, ans); } } path.pop_back(); }};
- 【leetcode】Word Ladder II
- [LeetCode]Word Ladder II
- [leetcode] Word Ladder II
- LeetCode - Word Ladder II
- Leetcode: Word Ladder II
- leetcode Word Ladder II
- Leetcode Word Ladder II
- LeetCode | Word Ladder II
- leetcode word ladder II
- 【Leetcode】Word Ladder II
- [LeetCode] Word Ladder II
- Word Ladder II -- LeetCode
- Leetcode: Word Ladder II
- leetcode-Word Ladder II
- leetcode-Word Ladder II
- leetcode: Word Ladder II
- leetcode Word Ladder II
- Leetcode: Word Ladder II
- SQL优化----百万数据查询优化
- 《编程之美》3.11 扩展问题
- iOS 开发异步 第三方库 PromiseKit 解析
- Could not load file or assembly or one of its dependencies. 试图加载格式不正确的程序。
- 编程范式,程序员的编程世界观
- Word Ladder II -- leetcode
- Java流详解
- 程序远表白网,对Ta Say Love
- 对公司所有员工的年龄排序
- oracle学习笔记10(监听器进程)
- 苹果开发 笔记(26)
- 异常
- Google maps API
- SQL 优化原则