Word Ladder系列
1.Word Ladder
问题描述:
给两个word(beginWord和endWord)和一个字典word list,找出从beginWord到endWord之间的长度最长的一个序列,条件:
1.字典中的每个单词只能使用一次;
2.序列中的每个单词都必须是字典中的单词;
例如:
Given:
beginWord = "hit"
endWord = "cog"
wordList = ["hot","dot","dog","lot","log"]
As one shortest transformation is "hit" -> "hot" -> "dot" -> "dog" -> "cog",
return its length 5.
注意:
如果找不到合适的序列,返回0;
所有的单词长度都是一样的;
所有的单词都只由小写字母组成。
思路:
采用DFS依次遍历
代码如下:
class Solution {
public:
int ladderLength(string beginWord, string endWord, unordered_set<string>& wordDict) {
unordered_set<string> s1 = {beginWord}; // Front end
unordered_set<string> s2 = {endWord}; // Back end
wordDict.erase(beginWord);
wordDict.erase(endWord);
return ladderLength(s1, s2, wordDict, );
}
private:
int ladderLength(unordered_set<string>& s1, unordered_set<string>& s2, unordered_set<string>& wordDict, int level) {
if (s1.empty()) // We can't find one.
return ;
unordered_set<string> s3; // s3 stores all words 1 step from s1.
for (auto word : s1) {
for (auto& ch : word) {
auto originalCh = ch;
for (ch = 'a'; ch <= 'z'; ++ ch) {
if (ch != originalCh) {
if (s2.count(word)) // We found one.
return level + ;
if (wordDict.count(word)) {
wordDict.erase(word); // Avoid duplicates.
s3.insert(word);
}
}
}
ch = originalCh;
}
}
// Continue with the one with smaller size.
return (s2.size() <= s3.size()) ? ladderLength(s2, s3, wordDict, level + ) : ladderLength(s3, s2, wordDict, level + );
}
};
1.Word Ladder II
问题描述:给两个word(beginWord和endWord)和一个字典word list,找出从beginWord到endWord之间所有长度最短的序列,条件:
1.一次只能改变一个字符
2.每个中间的单词必须在字典中
思路:
Treat each word as a node of a tree. There are two trees. One tree's root node is "beginWord", and the other tree's root node is "endWord".
The root node can yield all his children node, and they are the second layer of the tree. The second layer can yield all their children, then we get the third layer of the tree, ... , and so on.
When one tree yield a new child, we search it in the last layer of the other tree. If we find an identical node in that tree, then we get some ladders connect two roots("beginWord" -> ... -> "endWord").
Another thing should be considered is: two(or more) different nodes may yield an identical child. That means the child may have two(or more) parents. For example, "hit" and "hot" can both yield "hat", means "hat" has two parents.
So, the data struct of tree-node is:
class Node {
public:
string word;
vectror<Node*> parents;
Node(string w) : word(w) {}
}
Note: we don't need a children field for Node class, because we won't use it.
Two nodes are considered equal when their word field are equal. So we introduce an compare function:
bool nodecmp(Node* pa, Node* pb)
{
return pa->word < pb->word;
}
Then we use nodecmp as the compare function to build a node set.
typedef bool (*NodeCmper) (Node*, Node*);
typedef set<Node*, NodeCmper> NodeSet;
NodeSet layer(nodecmp);
Then we can store/search pointers of nodes in node set layer. For example:
Node node1("hit"), node2("hot"), node3("hat");
layer.insert(&node1);
layer.insert(&node2);
layer.insert(&node3);
auto itr = layer.find(new Node("hot"));
cout << (*itr)->word; // output: hot
Using these data structures, we can solve this problem with bi-direction BFS algorithm. Below is the AC code, and it is very very fast.
class Node; typedef vector<string> Ladder;
typedef unordered_set<string> StringSet;
typedef bool (*NodeCmper) (Node*, Node*);
typedef set<Node*, NodeCmper> NodeSet; class Node
{
public:
string word;
vector<Node*> parents; Node(string w) : word(w) {}
void addparent(Node* parent) { parents.push_back(parent); } // Yield all children of this node, and:
// 1) If the child is found in $targetlayer, which means we found ladders that
// connect BEGIN-WORD and END-WORD, then we get all paths through this node
// to its ROOT node, and all paths through the target child node to its ROOT
// node, and combine the two group of paths to a group of ladders, and append
// these ladders to $ladders.
// 2) Elif the $ladders is empty:
// 2.1) If the child is found in $nextlayer, then get that child, and add
// this node to its parents.
// 2.2) Else, add the child to nextlayer, and add this node to its parents.
// 3) Else, do nothing.
void yieldchildren(NodeSet& nextlayer, StringSet& wordlist, NodeSet& targetlayer,
vector<Ladder>& ladders, bool forward)
{
string nextword = word;
for (int i = , n = nextword.length(); i < n; i++) {
char oldchar = nextword[i];
for (nextword[i] = 'a'; nextword[i] <= 'z'; nextword[i]++) {
if (wordlist.count(nextword)) {
// now we found a valid child-word, let's yield a child.
Node* child = new Node(nextword);
yield1(child, nextlayer, targetlayer, ladders, forward);
}
}
nextword[i] = oldchar;
}
} // yield one child, see comment of function `yieldchildren`
void yield1(Node* child, NodeSet& nextlayer, NodeSet& targetlayer,
vector<Ladder>& ladders, bool forward) {
auto itr = targetlayer.find(child);
if (itr != targetlayer.end()) {
for (Ladder path1 : this->getpaths()) {
for (Ladder path2 : (*itr)->getpaths()) {
if (forward) {
ladders.push_back(path1);
ladders.back().insert(ladders.back().end(), path2.rbegin(), path2.rend());
} else {
ladders.push_back(path2);
ladders.back().insert(ladders.back().end(), path1.rbegin(), path1.rend());
}
}
}
} else if (ladders.empty()) {
auto itr = nextlayer.find(child);
if (itr != nextlayer.end()) {
(*itr)->addparent(this);
} else {
child->addparent(this);
nextlayer.insert(child);
}
}
} vector<Ladder> getpaths()
{
vector<Ladder> ladders;
if (parents.empty()) {
ladders.push_back(Ladder(, word));
} else {
for (Node* parent : parents) {
for (Ladder ladder : parent->getpaths()) {
ladders.push_back(ladder);
ladders.back().push_back(word);
}
}
}
return ladders;
}
}; bool nodecmp(Node* pa, Node* pb)
{
return pa->word < pb->word;
} class Solution {
public:
vector<Ladder> findLadders(string begin, string end, StringSet& wordlist) {
vector<Ladder> ladders;
Node headroot(begin), tailroot(end);
NodeSet frontlayer(nodecmp), backlayer(nodecmp);
NodeSet *ptr_layerA = &frontlayer, *ptr_layerB = &backlayer;
bool forward = true; if (begin == end) {
ladders.push_back(Ladder(, begin));
return ladders;
} frontlayer.insert(&headroot);
backlayer.insert(&tailroot);
wordlist.insert(end);
while (!ptr_layerA->empty() && !ptr_layerB->empty() && ladders.empty()) {
NodeSet nextlayer(nodecmp);
if (ptr_layerA->size() > ptr_layerB->size()) {
swap(ptr_layerA, ptr_layerB);
forward = ! forward;
}
for (Node* node : *ptr_layerA) {
wordlist.erase(node->word);
}
for (Node* node : *ptr_layerA) {
node->yieldchildren(nextlayer, wordlist, *ptr_layerB, ladders, forward);
}
swap(*ptr_layerA, nextlayer);
} return ladders;
}
};
Word Ladder系列的更多相关文章
- [LeetCode] Word Ladder 词语阶梯
Given two words (beginWord and endWord), and a dictionary, find the length of shortest transformatio ...
- [LeetCode] Word Ladder II 词语阶梯之二
Given two words (start and end), and a dictionary, find all shortest transformation sequence(s) from ...
- LeetCode:Word Ladder I II
其他LeetCode题目欢迎访问:LeetCode结题报告索引 LeetCode:Word Ladder Given two words (start and end), and a dictiona ...
- 【leetcode】Word Ladder
Word Ladder Total Accepted: 24823 Total Submissions: 135014My Submissions Given two words (start and ...
- 【leetcode】Word Ladder II
Word Ladder II Given two words (start and end), and a dictionary, find all shortest transformation ...
- 18. Word Ladder && Word Ladder II
Word Ladder Given two words (start and end), and a dictionary, find the length of shortest transform ...
- [Leetcode][JAVA] Word Ladder II
Given two words (start and end), and a dictionary, find all shortest transformation sequence(s) from ...
- LeetCode127:Word Ladder II
题目: Given two words (start and end), and a dictionary, find all shortest transformation sequence(s) ...
- 【LeetCode OJ】Word Ladder II
Problem Link: http://oj.leetcode.com/problems/word-ladder-ii/ Basically, this problem is same to Wor ...
随机推荐
- centos6启动故障排除
centos6中boot文件被全部删除的故障排除 /boot文件里关于启动的核心文件有三个,/vmlinuz-2.6.32-696.e16.x86_64,initramfs-2.6.32-696.el ...
- 拓展jQuery的serialize(),将form表单转化为json对象
jQuery 的 serialize() 方法经常会报 Uncaught TypeError: JSON.serializeObject is not a function 的错误, 原装的方法真的一 ...
- MySQL中文转换成拼音的函数
CREATE DEFINER=`root`@`localhost` FUNCTION `fristPinyin`(`P_NAME` VARCHAR(255) CHARSET utf8) RETURNS ...
- 解决oh-my-zsh卡顿问题
git config --global oh-my-zsh.hide-status 1
- Python头脑风暴2
今天想到了一个致富新途径:假如我在X东上班,我写个X宝爬虫,专门爬在X宝买奢侈品的土豪,然后我自己注册个X宝号,用脚本一个个加他们然后给他们发信息说我X东这还有比你更便宜更好的...不知道行不行啊(狗 ...
- SQL_4_函数
在SQL的函数中可以执行一些诸如对某一些进行汇总或将一个字符串中的字符转换为大写的操作等: 函数有:汇总函数.日期与时间函数.数学函数.字符函数.转换函数与其他函数. 汇总函数 这是一组函数,它们返回 ...
- HDU 5510 Bazinga KMP
题意: 给\(n(1 \leq n \leq 500)\)个字符串,求一个最大的\(i\),使得存在一个\(S_{j}\)不是\(S_i\)的子串. 分析: 维护两个指针\(l,r\) 那么有两种情况 ...
- js中的事件委托和事件代理详解
起因: 1.这是前端面试的经典题型,要去找工作的小伙伴看看还是有帮助的: 2.其实我一直都没弄明白,写这个一是为了备忘,二是给其他的知其然不知其所以然的小伙伴们以参考: 概述: 那什么叫事件委托呢?它 ...
- Good Bye 2017
太菜了啊,一不小心就goodbye rating了 A. New Year and Counting Cards time limit per test 1 second memory limit p ...
- JDBC 学习笔记(四)—— JDBC 加载数据库驱动,获取数据库连接
1. 加载数据库驱动 通常来说,JDBC 使用 Class 类的 forName() 静态方法来加载驱动,需要输入数据库驱动代表的字符串. 例如: 加载 MySQL 驱动: Class.forName ...