从word ladder题目看DFS和BFS(上)

最近在刷题并整理DFS和BFS的思路,有两道题引起了我的注意,就是leetcode上的126和127两个word ladder题目。

首先我们先来关注下这两道题的描述,127题只需要记录单词转换的最短路径长度就好,而126题需要记录所有最短转换路径。127题属于中等难度的题目,但是126题属于hard难度的题目。

127题描述:

Given two words (beginWord and endWord),and a dictionary's word list, find the length of shortest transformationsequence from beginWord to endWord, such that:

Only one letter can be changed at a time.

Each transformed word must exist in theword list. Note that beginWord is not a transformed word.

Note:

Return 0 if there is no such transformationsequence.

All words have the same length.

All words contain only lowercase alphabeticcharacters.

You may assume no duplicates in the wordlist.

You may assume beginWord and endWord arenon-empty and are not the same.

看到这个题,求最短路径,首先想到是用BFS来做,先将初始的单词放到队列里,层数置1,从开始的单词出发,每次变换一个字母位置,看变换之后的单词是否在字典里,如果在字典里,将单词放到队列中去,然后把这个单词从字典里删除,目的是为了防止重复计算而形成环。队列里加入“1”作为区分不同的层,等到出队元素是目标字符串时,停止遍历,返回当前的层数即可,这个思路很明了,很容易想到。

下面是按照这个思路的BFS代码:

class Solution {

public:

   int ladderLength(string beginWord, string endWord,vector<string>& wordList)

    {

       int n=beginWord.size();

       unordered_set<string> word(wordList.begin(),wordList.end());

       if(beginWord.size()!=endWord.size()) return 0;

       int step=1; //层数初始值为1

       bool exist=false; //是否存在转换路径

       queue<string> q;

       q.push(beginWord); //初始单词入队

       q.push("1"); //层间间隔标志是“1”

       while(!q.empty())

       {

           string temp=q.front();

           q.pop();

           if(temp==endWord) //当前出队元素是目标字符串,说明存在转换路径

           {

                exist=true;

                break; //找到路径,结束

           }

           if(temp=="1") //出队元素是层间间隔符号,说明当前一层遍历结束,层数加1

           {

                step++;

                continue;

           }

           for(int i=0;i<n;i++)  //逐个位置进行替换

           {

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

                {

                    string tmp=temp;

                    if(tmp[i]!=j) tmp[i]=j;

                    if(word.find(tmp)!=word.end())  //替换之后的单词在字典里

                    {

                        word.erase(tmp); //将该单词从字典中删除,避免成环

                        q.push(tmp); //该单词放到队列里

                    }

                }

           }

           if(!q.empty() && q.front()=="1")  //队首元素是“1”分隔符,说明当前层遍历结束,再加上一个层间分隔符

                q.push("1");

       }

       if(exist) return step; //如果存在转换路径,将结果路径长度输出,输出的是当前的层号

       return 0;

    }

};

 

在做这个题之前,我能想到用DFS,DFS的方案在于可以穷尽所有的路径,最后找出最短的那条。缺点在于,递归深度可能会很深,递归的树层数是字典的大小,如果字典很大的话,这个时间复杂度成指数增长,是灾难性的,因此这种方案会出现超时的状况,无法通过所有的样例。但是作为练习,我还是把这个题用DFS写了,仅供参考。

时间复杂度是O((n*26)^m)其中n是单词长度,m是字典大小。

代码如下:

class Solution

{

public:

   int ladderLength(string beginWord, string endWord,vector<string>& wordList)

    {

       int tmp=wordList.size();

       unordered_set<string> word(wordList.begin(),wordList.end());

       word.erase(beginWord);

       int max_i=wordList.size()+3; //路径长度最多为把所有的单词遍历一遍

       helper(beginWord,endWord,word,max_i,1);

       if(max_i<tmp+3)

           return max_i;

       else return 0;     

    }

   void helper(string beginWord, string endWord,unordered_set<string> &word, int &max_i,int cur_i)

    {

       if(beginWord==endWord) //递归出口,变换到目标单词时,结束

       {

           if(cur_i<max_i)  //打擂,找出最短的路径

                max_i=cur_i;

                     return;

       }

       if(word.size()==0) //不能变换到目标单词,单词表中的单词删除完毕,结束

       {

           return;

       }

       for(int j=0;j<beginWord.size();j++)

       {

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

          {

               if(beginWord[j]==i) continue;

               char tmp=beginWord[j];

               beginWord[j]=i;

              if(word.find(beginWord)!=word.end())

               {

                   word.erase(beginWord);

                  helper(beginWord,endWord,word,max_i,cur_i+1);

                   word.insert(beginWord); //恢复现场

               }

               beginWord[j]=tmp;

          }           

       }    

    }

};


阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

不良信息举报

从word ladder题目看DFS和BFS(上)

最多只允许输入30个字

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭