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系列的更多相关文章

  1. [LeetCode] Word Ladder 词语阶梯

    Given two words (beginWord and endWord), and a dictionary, find the length of shortest transformatio ...

  2. [LeetCode] Word Ladder II 词语阶梯之二

    Given two words (start and end), and a dictionary, find all shortest transformation sequence(s) from ...

  3. LeetCode:Word Ladder I II

    其他LeetCode题目欢迎访问:LeetCode结题报告索引 LeetCode:Word Ladder Given two words (start and end), and a dictiona ...

  4. 【leetcode】Word Ladder

    Word Ladder Total Accepted: 24823 Total Submissions: 135014My Submissions Given two words (start and ...

  5. 【leetcode】Word Ladder II

      Word Ladder II Given two words (start and end), and a dictionary, find all shortest transformation ...

  6. 18. Word Ladder && Word Ladder II

    Word Ladder Given two words (start and end), and a dictionary, find the length of shortest transform ...

  7. [Leetcode][JAVA] Word Ladder II

    Given two words (start and end), and a dictionary, find all shortest transformation sequence(s) from ...

  8. LeetCode127:Word Ladder II

    题目: Given two words (start and end), and a dictionary, find all shortest transformation sequence(s) ...

  9. 【LeetCode OJ】Word Ladder II

    Problem Link: http://oj.leetcode.com/problems/word-ladder-ii/ Basically, this problem is same to Wor ...

随机推荐

  1. OpenCV3.42+VS2017配置+模块计算机类型“X86”与目标计算机类型“x64”冲突”的问题解决

    目录 OpenCV3.42+VS2017配置 Visual Studio 2017 第三方依赖设置,附加依赖项和附加库目录 "fatal error LNK1112: 模块计算机类型&quo ...

  2. PAT 乙级 1088

    题目 题目链接:PAT 乙级 1088 题解 比较简单的一道题,下面来简单说说思路: 因为甲确定是一个两位数,因此通过简单的暴力循环求解甲的值,又根据题设条件“把甲的能力值的 2 个数字调换位置就是乙 ...

  3. 消息队列之JMS和AMQP对比

    https://blog.csdn.net/hpttlook/article/details/23391967 AMQP & JMS对比 初次接触消息队列时,在网上搜索,总是会提到如JMS.A ...

  4. LeetCode(189) Rotate Array

    题目 Rotate an array of n elements to the right by k steps. For example, with n = 7 and k = 3, the arr ...

  5. CentOS 7 安装 配置 Nginx + PHP

    . CentOS 7 下配置 yum 安装 Nginx. 进入/etc/yum.repos.d/目录下创建一个源配置文件nginx.repo: cd /etc/yum.repos.d/ vim ngi ...

  6. POJ:2109-Power of Cryptography(关于double的误差)

    Power of Cryptography Time Limit: 1000MS Memory Limit: 30000K Description Current work in cryptograp ...

  7. 并查集:CDOJ1594-老司机的奇幻漂流 (食物链)

    老司机的奇幻漂流 UESTC - 1594 Problem Description 老司机在救出了女票之后,就和她在全世界旅游,有一天,他们来到了一个神奇的小岛上. 这个小岛上有三种动物,他们互相克制 ...

  8. HDU 3727 Jewel 主席树

    题意: 一开始有一个空序列,然后有下面四种操作: Insert x在序列尾部加入一个值为\(x\)的元素,而且保证序列中每个元素都互不相同. Query_1 s t k查询区间\([s,t]\)中第\ ...

  9. UVa 10118 记忆化搜索 Free Candies

    假设在当前状态我们第i堆糖果分别取了cnt[i]个,那么篮子里以及口袋里糖果的个数都是可以确定下来的. 所以就可以使用记忆化搜索. #include <cstdio> #include & ...

  10. 和为n连续正数序列 【微软面试100题 第五十一题】

    题目要求: 输入一个正数n,输出所有和为n连续正数序列(至少两个). 例如输入15,由于1+2+3+4+5 = 4+5+6 = 7+8 = 15.所以输出3个连续序列1~5,4~6,7~8. 参考资料 ...