zoukankan      html  css  js  c++  java
  • world ladder

    转载:http://blog.csdn.net/zxzxy1988/article/details/8591890

     

    这道题目推荐和Leetcode 102 Binary Tree Level Order Traversal(http://blog.csdn.net/zxzxy1988/article/details/8597354)连起来看

     

    这道题目首先想到的是DFS,或曰backtracking,也就是每次都找到一个可能的路径,最后比较所有路径中最小的就是题目所求。这样做显然需要较多的时间,因为我们遍历了所有的可能性。那么,有没有更加快捷的方案呢?
    答案是显然的,那就是BFS。CareerCup上有这道题目,当时没有注意总结成这么抽象的方法,这次一定要好好总结一下。首先,虽然题目中没有一个“图”的概念,但是我们可以假想构建一个图,其中图中的每个顶点都是我们的元素,点和点是如何联系起来的呢?如果一个单词通过改变一次字母,能够变成另外一个单词,我们称之为1 edit distance 距离(是不是想起了leetcode中edit distance那道题目了?)所以,图中的所有相邻元素都是edit distance 距离为1的元素。那么,我们只需要做BFS,哪里最先遇到我们的target word,那么我们的距离就是多少。如果遍历完所有的元素都没有找到target word,那么我们就返回1。
    另外一个需要注意的地方就是,如果我们曾经遍历过某个元素,我会将其从字典中删除,以防以后再次遍历到这个元素。这里有几种情况:
    1.以后再也遍历不到这个元素,那么我们删除它当然没有任何问题。
    2.我们以后会遍历到该元素,又分为两种情况:
    (1)在本层我们就能遍历到该元素。也就是说,我们到达这个元素有两条路径,而且它们都是最短路径。
    举一个例子应该比较容易理解:比如hot->hog->dog->dig和hot->dot->dog->dig,那么在第一次遍历距离hot为1的元素时,我们找到了hog和dot。对hog遍历时,我们找到了dog,并且将其从字典中删除。那么在遍历距离dot为1的元素时,我们实际上是找不到dog的,因为已经被删除了。对于本题来说,是没有什么影响的,因为到dog距离都是3,到dig距离都是4。但是后面我们做word ladder 2的时候,如果没有考虑这个情况,将是非常致命的,因为题目要求输出最短路径的所有情况,我们稍后讨论相关问题
    (2)在更下层我们才能够遍历到该元素。比如hot->dot->dog->dig和hot->hat->dat->dag->dog->dig,如果第一次我们找到了dog并且将其删除,那么第二次我们实际上是找不到这个元素的。这样对于本题来说,没有任何影响。对于word ladder 2来说,因为也是要输出最短路径,所以也不会有任何影响。但是倘若我们要输出从起点到终点的所有路径,那么我们就要小心这种情况了。


    所以,从这里我们也能够得到这样一个结论:对于题目来说,一定要深刻理解每一步为什么要这样做。因为每种方式或多或少都会根据题目的特性做一些优化(比如word ladder I 和word ladder II),不仅仅要知道为什么要做优化,而且要知道优化的代价是什么,在什么情况下适用,什么情况下不适用。
    另外一点就是,每做一道题目都要好好总结一下,看看通过这道题目能够学会什么。好的题目,应该是会学会一个更加一般性的方法。现在没有时间去看CLRS,但是好好总结每一道题目,学会的方法也不会少。



    几个程序中需要注意的细节:
    1. ditance变量应该初始化为1。这个其实没有定数,不过根据题目的要求,比如hot->hog->dog,距离是3,由于我们每次distance只有在变化的时候才能增加(也就是说,我们这个变量实际上反映的是,我们“变化”了多少层),所以应该初始化为1
    2.如何初始化一个string。由于queue.front()返回的是元素的引用,因此我们必须拷贝那个变量,所以使用string str(queToPop.front());来初始化,然后将元素pop。
    3.C++中,实际上提供了swap函数的模板,不得不说还是很方便的。

     

     

    BFS method: 616ms to pass large set

     

    1. class Solution  
    2. {  
    3. public:  
    4.     int ladderLength(string start, string end, unordered_set<string> &dict)  
    5.     {  
    6.         if (start.size() != end.size())  
    7.             return 0;  
    8.         if (start.empty() || end.empty())  
    9.             return 1;  
    10.         if (dict.size() == 0)  
    11.             return 0;  
    12.         int distance = 1; //!!!  
    13.         queue<string> queToPush, queToPop;  
    14.         queToPop.push(start);  
    15.         while (dict.size() > 0 && !queToPop.empty())  
    16.         {  
    17.             while (!queToPop.empty())  
    18.             {  
    19.                 string str(queToPop.front()); //!!!how to initialize the str  
    20.                 queToPop.pop(); //!!! should pop after it is used up  
    21.                 for (int i = 0; i < str.size(); i++)  
    22.                 {  
    23.                     for (char j = 'a'; j <= 'z'; j++)  
    24.                     {  
    25.                         if (j == str[i])  
    26.                             continue;  
    27.                         char temp = str[i];  
    28.                         str[i] = j;  
    29.                         if (str == end)  
    30.                             return distance + 1; //found it  
    31.                         if (dict.count(str) > 0) //exists in dict  
    32.                         {  
    33.                             queToPush.push(str); //find all the element that is one edit away  
    34.                             dict.erase(str); //delete corresponding element in dict in case of loop  
    35.                         }  
    36.                         str[i] = temp; //  
    37.                     }  
    38.                 }  
    39.             }  
    40.             swap(queToPush, queToPop); //!!! how to use swap  
    41.             distance++;  
    42.         } //end while  
    43.         return 0; //all the dict words are used up and we do not find dest word  
    44.     } //end function  
    45. };  



     

     

    DFS method, Time Limit Exceed in large set:

     

    1. class Solution  
    2. {  
    3. public:  
    4.     //when the two words are equal, we also must change 1 character at one time  
    5.     int Helper(string current, string dest, unordered_set<string>& dict,  
    6.             bool isFirstCall)  
    7.     {  
    8.         int ret = INT_MAX;  
    9.         if (current == dest && !isFirstCall)  
    10.             return 1; //the step to get here  
    11.         if (dict.empty())  
    12.             return INT_MAX; //the dict is used up but we do not get the dest  
    13.         for (int i = 0; i < current.size(); i++)  
    14.             for (int j = 'a'; j <= 'z'; j++)  
    15.             {  
    16.                 if (j == current[i]) //skip the current character  
    17.                     continue;  
    18.                 char temp = current[i];  
    19.                 current[i] = j;  
    20.                 if (dict.count(current) > 0) //exist such a word in the dict  
    21.                 {  
    22.                     dict.erase(current); //delete such a word  
    23.                     int rettemp = Helper(current, dest, dict);  
    24.                     if (rettemp != INT_MAX) //have found dest  
    25.                     {  
    26.                         ret = min(rettemp + 1, ret);  
    27.                     }  
    28.   
    29.                     dict.insert(current);  
    30.                 }  
    31.                 //pay attention to how to restore the element  
    32.                 //restore in the corresponding nesting!  
    33.                 current[i] = temp;  
    34.   
    35.             }  
    36.         //ret can be INT_MAX or the distance value  
    37.         //if we do not find any 1 edit distance word in dict, return fail      
    38.         return ret;  
    39.     }  
    40.       
    41.     int ladderLength(string start, string end, unordered_set<string> &dict)  
    42.     {  
    43.         if (start.size() != end.size())  
    44.             return 0;  
    45.         if (start.empty() || end.empty() || dict.empty())  
    46.             return 0;  
    47.         bool isEqual = false;  
    48.         if (start == end)  
    49.             isEqual = true;  
    50.         int temp = Helper(start, end, dict, isEqual);  
    51.         if (temp == INT_MAX)  
    52.             return 0;  
    53.         else  
    54.             return temp;  
    55.     }  
    56. };  
  • 相关阅读:
    非常强大的table根据表头排序,点击表头名称,对其内容排序
    处理字符集中的算式问题
    java基础复习:final,static,以及String类
    try,catch,finally含return时的执行顺序及丢失的伪例
    系统 触发器
    某个表按某个列分组且按另一个列排序
    XML读取
    硬软件交互原理
    TcpClient 读写流
    C# Socket的TCP通讯 异步 (2015-11-07 10:07:19)转载▼
  • 原文地址:https://www.cnblogs.com/ldjhust/p/3181562.html
Copyright © 2011-2022 走看看