Word Ladder

Given two words (start and end), and a dictionary, find the length of shortest transformation sequence from start to end, such that:

  1. Only one letter can be changed at a time
  2. Each intermediate word must exist in the dictionary

For example,

Given:
start = "hit"
end = "cog"
dict = ["hot","dot","dog","lot","log"]

As one shortest transformation is "hit" -> "hot" -> "dot" -> "dog" -> "cog",
return its length 5.

Note:

    • Return 0 if there is no such transformation sequence.
    • All words have the same length.
    • All words contain only lowercase alphabetic characters.

这道题目首先想到的是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来说,因为也是要输出最短路径,所以也不会有任何影响。但是倘若我们要输出从起点到终点的所有路径,那么我们就要小心这种情况了。参考:http://blog.csdn.net/zxzxy1988/article/details/8591890

 

这道题看似一个关于字符串操作的题目,其实要解决这个问题得用图的方法。我们先给题目进行图的映射,顶点则是每个字符串,然后两个字符串如果相差一个字符则我们进行连边。接下来看看这个方法的优势,注意到我们的字符集只有小写字母,而且字符串长度固定,假设是L。那么可以注意到每一个字符可以对应的边则有25个(26个小写字母减去自己),那么一个字符串可能存在的边是25*L条。接下来就是检测这些边对应的字符串是否在字典里,就可以得到一个完整的图的结构了。根据题目的要求,等价于求这个图一个顶点到另一个顶点的最短路径,一般我们用广度优先搜索。这个算法中最坏情况是把所有长度为L的字符串都看一下,或者把字典中的字符串都看一下,而长度为L的字符串总共有26^L,所以时间复杂度是O(min(26^L, size(dict)),空间上需要存储访问情况,也是O(min(26^L, size(dict))。

 

C++实现代码:

#include<iostream>

#include<string>

#include<unordered_set>

#include<queue>

using namespace std;



class Solution

{

public:

    int ladderLength(string start, string end, unordered_set<string> &dict)

    {

        if(start.empty()||end.empty()||dict.empty())

            return 0;

        int level=1;

        int count=0;

        int curr=0;

        int i;

        queue<string> q;

        q.push(start);

        count++;

        while(!q.empty())

        {

            string tmp=q.front();

            q.pop();

            count--;

            for(i=0; i<(int)tmp.size(); i++)

            {

                char ctmp=tmp[i];

                for(char c='a'; c<='z'; c++)

                {

                    if(tmp[i]==c)

                        continue;

                    tmp[i]=c;

                    if(tmp==end)

                        return level+1;

                    if(dict.count(tmp)>0)

                    {

                        q.push(tmp);

                        curr++;

                        dict.erase(tmp);

                    }

                    tmp[i]=ctmp;

                }

            }

            if(count==0)

            {

                level++;

                count=curr;

                curr=0;

            }

        }

        return 0;

    }

};



int main()

{

    Solution s;

    string start = "hot";

    string end = "dog";

    unordered_set<string> dict = {"hot","dog"};

    cout<<s.ladderLength(start,end,dict)<<endl;

}

 

你可能感兴趣的:(word)