zoukankan      html  css  js  c++  java
  • 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依次遍历

    代码如下:

     

     1 class Solution {
     2 public:
     3     int ladderLength(string beginWord, string endWord, unordered_set<string>& wordDict) {
     4         unordered_set<string> s1 = {beginWord}; // Front end
     5         unordered_set<string> s2 = {endWord}; // Back end
     6         wordDict.erase(beginWord);
     7         wordDict.erase(endWord);
     8 
     9         return ladderLength(s1, s2, wordDict, 1);
    10     }
    11     
    12 private:
    13     int ladderLength(unordered_set<string>& s1, unordered_set<string>& s2, unordered_set<string>& wordDict, int level) {
    14         if (s1.empty()) // We can't find one.
    15             return 0;
    16         unordered_set<string> s3; // s3 stores all words 1 step from s1.
    17         for (auto word : s1) {
    18             for (auto& ch : word) {
    19                 auto originalCh = ch;
    20                 for (ch = 'a'; ch <= 'z'; ++ ch) {
    21                     if (ch != originalCh) {
    22                         if (s2.count(word))  // We found one.
    23                             return level + 1;
    24                         if (wordDict.count(word)) {
    25                             wordDict.erase(word); // Avoid duplicates.
    26                             s3.insert(word);
    27                         }
    28                     }
    29                 }
    30                 
    31                 ch = originalCh;
    32             }
    33         }
    34         // Continue with the one with smaller size.    
    35         return (s2.size() <= s3.size()) ? ladderLength(s2, s3, wordDict, level + 1) : ladderLength(s3, s2, wordDict, level + 1);
    36     }
    37 };

     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:

    1 class Node {
    2 public: 
    3     string word;
    4     vectror<Node*> parents;
    5     Node(string w) : word(w) {}
    6 }

    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:

    1 bool nodecmp(Node* pa, Node* pb)
    2 {
    3     return pa->word < pb->word;
    4 }

    Then we use nodecmp as the compare function to build a node set.

    1 typedef bool (*NodeCmper) (Node*, Node*);
    2 typedef set<Node*, NodeCmper> NodeSet;
    3 NodeSet layer(nodecmp);

    Then we can store/search pointers of nodes in node set layer. For example:

    1 Node node1("hit"), node2("hot"), node3("hat");    
    2 layer.insert(&node1);
    3 layer.insert(&node2);
    4 layer.insert(&node3);
    5 auto itr = layer.find(new Node("hot"));
    6 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.

      1 class Node;
      2 
      3 typedef vector<string> Ladder;
      4 typedef unordered_set<string> StringSet;
      5 typedef bool (*NodeCmper) (Node*, Node*);
      6 typedef set<Node*, NodeCmper> NodeSet;
      7 
      8 class Node
      9 {
     10 public:
     11     string word;
     12     vector<Node*> parents;
     13 
     14     Node(string w) : word(w) {}
     15     void addparent(Node* parent) { parents.push_back(parent); }
     16 
     17     // Yield all children of this node, and:
     18     //   1) If the child is found in $targetlayer, which means we found ladders that
     19     //      connect BEGIN-WORD and END-WORD, then we get all paths through this node
     20     //      to its ROOT node, and all paths through the target child node to its ROOT
     21     //      node, and combine the two group of paths to a group of ladders, and append
     22     //      these ladders to $ladders.
     23     //   2) Elif the $ladders is empty:
     24     //       2.1) If the child is found in $nextlayer, then get that child, and add
     25     //            this node to its parents.
     26     //       2.2) Else, add the child to nextlayer, and add this node to its parents.
     27     //   3) Else, do nothing.
     28     void yieldchildren(NodeSet& nextlayer, StringSet& wordlist, NodeSet& targetlayer,
     29                        vector<Ladder>& ladders, bool forward)
     30     {
     31         string nextword = word;
     32         for (int i = 0, n = nextword.length(); i < n; i++) {
     33             char oldchar = nextword[i];
     34             for (nextword[i] = 'a'; nextword[i] <= 'z'; nextword[i]++) {
     35                 if (wordlist.count(nextword)) {
     36                     // now we found a valid child-word, let's yield a child.
     37                     Node* child = new Node(nextword);
     38                     yield1(child, nextlayer, targetlayer, ladders, forward);
     39                 }
     40             }
     41             nextword[i] = oldchar;
     42         }
     43     }
     44 
     45     // yield one child, see comment of function `yieldchildren`
     46     void yield1(Node* child, NodeSet& nextlayer, NodeSet& targetlayer,
     47                 vector<Ladder>& ladders, bool forward) {
     48         auto itr = targetlayer.find(child);
     49         if (itr != targetlayer.end()) {
     50             for (Ladder path1 : this->getpaths()) {
     51                 for (Ladder path2 : (*itr)->getpaths()) {
     52                     if (forward) {
     53                         ladders.push_back(path1);
     54                         ladders.back().insert(ladders.back().end(), path2.rbegin(), path2.rend());
     55                     } else {
     56                         ladders.push_back(path2);
     57                         ladders.back().insert(ladders.back().end(), path1.rbegin(), path1.rend());
     58                     }
     59                 }
     60             }
     61         } else if (ladders.empty()) {
     62             auto itr = nextlayer.find(child);
     63             if (itr != nextlayer.end()) {
     64                 (*itr)->addparent(this);
     65             } else {
     66                 child->addparent(this);
     67                 nextlayer.insert(child);
     68             }
     69         }
     70     }
     71 
     72     vector<Ladder> getpaths()
     73     {
     74         vector<Ladder> ladders;
     75         if (parents.empty()) {
     76             ladders.push_back(Ladder(1, word));
     77         } else {
     78             for (Node* parent : parents) {
     79                 for (Ladder ladder : parent->getpaths()) {
     80                     ladders.push_back(ladder);
     81                     ladders.back().push_back(word);
     82                 }
     83             }
     84         }
     85         return ladders;
     86     }
     87 };
     88 
     89 bool nodecmp(Node* pa, Node* pb)
     90 {
     91     return pa->word < pb->word;
     92 }
     93 
     94 class Solution {
     95 public:
     96     vector<Ladder> findLadders(string begin, string end, StringSet& wordlist) {
     97         vector<Ladder> ladders;
     98         Node headroot(begin), tailroot(end);
     99         NodeSet frontlayer(nodecmp), backlayer(nodecmp);
    100         NodeSet *ptr_layerA = &frontlayer, *ptr_layerB = &backlayer;
    101         bool forward = true;
    102 
    103         if (begin == end) {
    104             ladders.push_back(Ladder(1, begin));
    105             return ladders;
    106         }
    107 
    108         frontlayer.insert(&headroot);
    109         backlayer.insert(&tailroot);
    110         wordlist.insert(end);
    111         while (!ptr_layerA->empty() && !ptr_layerB->empty() && ladders.empty()) {
    112             NodeSet nextlayer(nodecmp);
    113             if (ptr_layerA->size() > ptr_layerB->size()) {
    114                 swap(ptr_layerA, ptr_layerB);
    115                 forward = ! forward;
    116             }
    117             for (Node* node : *ptr_layerA) {
    118                 wordlist.erase(node->word);
    119             }
    120             for (Node* node : *ptr_layerA) {
    121                 node->yieldchildren(nextlayer, wordlist, *ptr_layerB, ladders, forward);
    122             }
    123             swap(*ptr_layerA, nextlayer);
    124         }
    125 
    126         return ladders;
    127     }
    128 };
  • 相关阅读:
    10.25 测试
    ##2018-2019-1 20165327 《信息安全系统设计基础》第四周学习总结
    实验一 开发环境的熟悉
    ch03 课下作业——缓冲区溢出漏洞实验
    20165327 2018-2017-1 《信息安全系统设计基础》第三周学习总结
    week02 课堂作业
    第四周学习总结
    2018-2019-1 20165204 《信息安全系统设计基础》第三周学习总结
    2018-2019-1 20165204《信息安全系统设计基础》第二周学习总结
    2018-2019-1 20165204 《信息安全系统设计基础》第一周学习总结
  • 原文地址:https://www.cnblogs.com/SarahLiu/p/5976640.html
Copyright © 2011-2022 走看看