Leetcode#126 Word Ladder II
既然是求最短路径,可以考虑动归或广搜。这道题对字典直接进行动归是不现实的,因为字典里的单词非常多。只能选择广搜了。
思路也非常直观,从start或end开始,不断加入所有可到达的单词,直到最终到达另一端。本质上广度优先遍历图。
需要注意的是,拓展下一个单词时不能对字典进行枚举,因为字典里的单词太多。幸好单词本身都不长,所以直接枚举单词所有可能的变形,看看在dict中出现没有。
当然还不止这些,上面的做法仍然会超时,需要添加剪枝策略:
1. 如果某个单词在以前遍历过了,那么以后都不用再考虑,因为之后遍历到的路径一定不是最短的
2. 在广搜法拓展下一轮单词时,注意去重
此外还需要注意的是,不能把每个单词到start或end的路径都保存下来,那样内存会爆掉。所以要压缩保存结果,通常的做法是用一个map保存当前单词下一步是什么单词。例如next[word] = {next_word1, next_word2, next_word3...}。最后从next[start]开始再次使用广度优先搜索法构造出所有解。
算法不难,但是编码非常容易出错,所以总体上还是挺难的。最后运行时间640ms,还是有挺大优化空间的。
代码写的有些啰嗦,DFS不一定要用队列(我还是用了队列),这道题用unordered_set更好,不需要用额外的数据结构去重了。
代码:
bool adjacentp(string &a, string &b) {
for (int i = a.length() - , d = ; i >= ; i--) {
d += a[i] != b[i] ? : ;
if (d > )
return false;
}
return true;
}
vector<vector<string> > findLadders(string start, string end, unordered_set<string> &dict) {
map<string, set<string> > next;
unordered_set<string> covered; // 当前已经访问过的单词
queue<string> que;
bool found = false; // 是否已经找到
next[end] = set<string>();
covered.insert(end);
que.push(end);
while (!que.empty() && !found) {
unordered_set<string> rset;
queue<string> rque;
while (!que.empty()) {
string curr = que.front();
que.pop();
if (adjacentp(curr, start)) {
found = true;
next[start].insert(curr);
continue;
}
for (int i = curr.length() - ; i >= ; i--) {
for (int j = ; j < ; j++) {
string prev = curr;
prev[i] = 'a' + j;
// 如果prev之前没有被访问过,且字典里有这个单词
if (covered.find(prev) == covered.end() && dict.find(prev) != dict.end()) {
next[prev].insert(curr);
// 如果在DFS的本轮拓展中还没有访问过该节点,则加入下一轮的拓展节点中
if (rset.find(prev) == rset.end()) {
rset.insert(prev);
rque.push(prev);
}
}
}
}
}
que = rque;
for (auto w : rset) {
covered.insert(w);
}
}
queue<vector<string> > laddersQue;
vector<vector<string> > ladders;
laddersQue.push(vector<string>(, start));
while (!laddersQue.empty()) {
vector<string> ladder = laddersQue.front();
laddersQue.pop();
if (ladder.back() == end)
ladders.push_back(ladder);
else {
for (auto s : next[ladder.back()]) {
vector<string> newLadder = ladder;
newLadder.push_back(s);
laddersQue.push(newLadder);
}
}
}
return ladders;
}
Leetcode#126 Word Ladder II的更多相关文章
- Java for LeetCode 126 Word Ladder II 【HARD】
Given two words (start and end), and a dictionary, find all shortest transformation sequence(s) from ...
- [LeetCode] 126. Word Ladder II 词语阶梯 II
Given two words (beginWord and endWord), and a dictionary's word list, find all shortest transformat ...
- LeetCode 126. Word Ladder II 单词接龙 II(C++/Java)
题目: Given two words (beginWord and endWord), and a dictionary's word list, find all shortest transfo ...
- [LeetCode] 126. Word Ladder II 词语阶梯之二
Given two words (beginWord and endWord), and a dictionary's word list, find all shortest transformat ...
- leetcode 126. Word Ladder II ----- java
Given two words (beginWord and endWord), and a dictionary's word list, find all shortest transformat ...
- leetcode@ [126] Word Ladder II (BFS + 层次遍历 + DFS)
https://leetcode.com/problems/word-ladder-ii/ Given two words (beginWord and endWord), and a diction ...
- leetcode 127. Word Ladder、126. Word Ladder II
127. Word Ladder 这道题使用bfs来解决,每次将满足要求的变换单词加入队列中. wordSet用来记录当前词典中的单词,做一个单词变换生成一个新单词,都需要判断这个单词是否在词典中,不 ...
- 126. Word Ladder II(hard)
126. Word Ladder II 题目 Given two words (beginWord and endWord), and a dictionary's word list, find a ...
- [Leetcode Week5]Word Ladder II
Word Ladder II 题解 原创文章,拒绝转载 题目来源:https://leetcode.com/problems/word-ladder-ii/description/ Descripti ...
随机推荐
- fancybox去除不受待见的水平滚动条
用fancybox在嵌套某个页面时,有时莫名其妙的会出现的消除不掉的幽灵般水平滚动条,如何去除: github上的解决方案:https://github.com/fancyapps/fancyBox/ ...
- 使用WIF实现单点登录Part IV —— 常见问题
InvalidOperationException: ID1073: 尝试使用 ProtectedData API 解密 Cookie 时出现 CryptographicException (有关详细 ...
- partition实现
partition的作用是把环形缓冲区中的map输出分区存储,以便分配给不同的reducer. 把内部的实现写下来,作为一个学习笔记 在map函数,调用context.write()时,会去调用分区函 ...
- 第七节:使用实现了dispose模式的类型
知道类型如何实现dispose模式之后,接下来看一下开发人员怎样使用提供了dispose模式的类型.这里不再讨论前面的SafeHandle类,而是讨论更常用的FileStream类. 可以利用File ...
- LinqToSql和ASP.NET Entity FrameWork 中使用事务
ASP.NET Entity FrameWork中: int flag = -1; if (this.URPmanagementEntities1.Connection.State != System ...
- Python学习教程(learning Python)--2.3.1 Python传参函数设计
本节主要讨论设计传递多个参数子函数的设计方法. 在2.3节里我们讨论了如何自己设计一个带参数的子函数的设计方法,现在我们研究一下如何传递两个及以上参数的设计方法. 函数为何要带参数呢?其实原因很简单, ...
- DataGridView的DataGridViewCheckBox问题
datagridview有一列DataGridViewCheckBox,但连续点击的话(1秒点击N次),会导致出错,数据处理不正确,感觉 private void dgv_CellContentCli ...
- eclipse java 空心J文件的回复
eclipse中的空心J的java文件,表示当前文件不包含在项目中进行编译,而仅仅是当做资源存在项目中. 解决方案如下: 1.鼠标右击当前空心j文件,-->build path-->inc ...
- Percona-Xtrabackup 2.3.3 慢查询依旧堵塞MariaDB备份(三)
MariaDB [yoon]> select version();+---------------------+| version() |+---------------------+| 10. ...
- 最简单的耗时组件(窗口activity里面放一个progressBar)
①.先定义一个activity package com.example.administrator.actionbardemo; import android.app.Activity; import ...