LeetCode OJ——Word Ladder

http://oj.leetcode.com/problems/word-ladder/

图的最短路径问题,可以用最短路径算法,也可以深搜,也可以广搜。

深搜版本:

第一次写的时候,把sum和visited都自然的设置成了传引用,导致递归调用下去之后,再返回来,反而各种参数的值退不回来了。然后把sum和visited改成了传值,这样反而适应了本程序意图。可见,也不是什么时候都需要传引用的。具体在写程序的时候,需要传值还是传引用,要具体分析。传引用和传值的情况分别如下:

void DFS(string currentWord,string endWord,int &sum, unordered_set<string> &dict,map<string,bool>  &visited,int  &minDistance)
void DFS(string currentWord,string endWord,int &sum, unordered_set<string> &dict,map<string,bool>  &visited,int  &minDistance)
另外,还遇到了一个问题,在递归调用层次下去又上来后,对本层循环的,后续影响。所以又添加了两个变量,int tempSum;和map<string,bool> tempVisited;。给它们赋值成参数刚进来的样子,这样就摒除了同层循环间的相互影响。

深搜版本超时了,继续改……
#include <iostream>
#include <vector>
#include <string>
#include <unordered_set>
#include <map>
#include <hash_map>
#include <limits.h>
using namespace std;

class Solution {
public:

    int calcDistance(string a,string b)
    {
        int sum = 0;
        for(int i = 0;i<a.size();i++)
        {
            if(a[i]!=b[i])
                sum++;
        }
        return sum;
    }
 
    void DFS(string currentWord,string endWord,int  sum, unordered_set<string> &dict,map<string,bool>  visited,int  &minDistance)
    {
        if(calcDistance(currentWord,endWord)==1)
        {
            sum++;
            if(minDistance>  sum)
                minDistance =  sum;
            return;
        }
        int tempSum;
        map<string,bool> tempVisited;
        for(unordered_set<string>::iterator iter = dict.begin();iter!=dict.end();iter++)
        {
            if(visited[*iter]==false && calcDistance(currentWord,*iter)==1)
            {
                visited[*iter] = true;
                tempSum = sum;
                tempSum++;
                tempVisited = visited;
                DFS(*iter,endWord,tempSum,dict,visited,minDistance);
            }
        }
    }
    
    
    int ladderLength(string start, string end, unordered_set<string> &dict) {

        string currentWord = start;

        int sum = 1;

        map<string,bool> visited;

        for(unordered_set<string>::iterator iter = dict.begin();iter!=dict.end();iter++)
            visited[*iter] = false;

        int minDistance = INT_MAX;

        DFS(currentWord,end,sum,dict,visited,minDistance);

        
        return  minDistance;
    }
};


    int main()
    {
        Solution *mySolution = new Solution();
         
        unordered_set<string> dict;
        dict.insert("hot");
        dict.insert("dot");
        dict.insert("dog");
        dict.insert("lot");
        dict.insert("log"); 
        string start = "hit";
        string end = "cog";
 
        cout<<mySolution->ladderLength(start,end,dict);
        return 0;
    }

 然后,写了一个广搜版本的,代码如下:

class Solution {

public:
    class node{
    public:
        int distance;
        string word;
        bool visited;
    public:
        node()
        {
            distance = 1;
            word.clear();
            visited = false;
        }
    };

    int testDistance(string test,string end)
    {
        int distance = 0;
        for(int i = 0;i<test.size();i++)
            if(test[i]!= end[i])
                distance++;
        return distance;
    }

   int ladderLength(string start, string end, unordered_set<string> &dict) {
       
       vector<node*> wordVector;

       unordered_set<string>::iterator itor=dict.begin();
       
       for(int i = 0;i<dict.size();i++)
       {
           node *myNode = new node();
           myNode->word = *itor;
           itor++;
           wordVector.push_back(myNode);
       }
       
       node *myNode = new node();
       myNode->word = start;

       queue<node*> wordQueue;
       wordQueue.push(myNode);

       node *topNode= new node();
       
       while(!wordQueue.empty())
       {
           topNode = wordQueue.front();
           wordQueue.pop();
           if(testDistance(topNode->word,end) == 1)
           {
               return topNode->distance+1;
           }
           else
           {
               node *pIndexNode = new node();
               for(vector<node*>::iterator itor = wordVector.begin();itor!=wordVector.end();itor++)
               {
                   pIndexNode = *itor;
                   if(pIndexNode->visited == false && testDistance(pIndexNode->word,topNode->word)==1)
                   {
                       pIndexNode->visited = true;
                       pIndexNode->distance = topNode->distance+1;
                       wordQueue.push(pIndexNode);
                   }
               }
           }
       }
 
   }
};

在这个过程中,刚开始写的是

return topNode->distance++;就直接这样返回了,写程序过程中,细心不够,这样返回是distance本来的值,然后distance会++,但是那也没用了。

仍然没过。但是相比之下,广搜比深搜,在测试数据上有进步了。继续改进广搜版本,将testDistance函数改了,并且还是用了eraser函数,将已经加入过的元素删除了,代码如下:

#include <iostream>
#include <vector>
#include <string>
#include <unordered_set>
#include <queue>
using namespace std;

class Solution {
public:
    class node{
    public:
        int distance;
        string word;
    public:
        node()
        {
            distance = 1;
            word.clear();
        }
    };

    bool testDistance(string test,string end)
    {
        int distance = 0;
        for(int i = 0;i<test.size();i++)
        {
            if(test[i]!= end[i])
                distance++;
            if(distance>=2)
                return false;
        }
        return true;
    }

   int ladderLength(string start, string end, unordered_set<string> &dict) {
       
       vector<node*> wordVector;

       unordered_set<string>::iterator itor=dict.begin();
       
       for(int i = 0;i<dict.size();i++)
       {
           node *myNode = new node();
           myNode->word = *itor;
           itor++;
           wordVector.push_back(myNode);
       }
       
       node *myNode = new node();
       myNode->word = start;

       queue<node*> wordQueue;
       wordQueue.push(myNode);

       node *topNode= new node();
       
       while(!wordQueue.empty())
       {
           topNode = wordQueue.front();
           wordQueue.pop();
           if(testDistance(topNode->word,end))
           {
               return topNode->distance+1;
           }
           else
           {
               node *pIndexNode = new node();
               for(vector<node*>::iterator itor = wordVector.begin();itor!=wordVector.end();)
               {
                   pIndexNode = *itor;
                   if(testDistance(pIndexNode->word,topNode->word))
                   {
                       pIndexNode->distance = topNode->distance+1;
                       wordQueue.push(pIndexNode);
                       itor = wordVector.erase(itor);
                   }
                   else
                       itor++;
               }
           }
       }
 
   }
};


    int main()
    {
        Solution *mySolution = new Solution();
         
        unordered_set<string> dict;
        dict.insert("hot");
        dict.insert("dot");
        dict.insert("dog");
        dict.insert("lot");
        dict.insert("log"); 
        string start = "hit";
        string end = "cog";
 
        cout<<mySolution->ladderLength(start,end,dict);
        return 0;
    }

虽然每一步都有学习到新东西,也学会了些深搜和广搜,但是这道题目仍然超时,现在考虑用空间换时间。

#include <iostream>
#include <vector>
#include <string>
#include <unordered_set>
#include <unordered_map>
#include <queue>
using namespace std;

class Solution {
public:
    bool testDistance(string test,string end)
    {
        int distance = 0;
        for(int i = 0;i<test.size();i++)
        {
            if(test[i]!= end[i])
                distance++;
            if(distance>=2)
                return false;
        }
        return true;
    }

    void BuildAdjacentList(string &word, unordered_map< string,unordered_set<string> >&adjacentList,const unordered_set<string> &dict)
    {
        string original = word;
        for(size_t pos = 0;pos<word.size();pos++)
        {
            char beforeChange = ' ';
            for(int i = 'a';i<'z';++i)
            {
                beforeChange = word[pos];
                if(beforeChange == i)
                {
                    continue;
                }
                word[pos] = i;
                if(dict.count(word)>0)
                {
                    auto iter = adjacentList.find(original);
                    if(iter!= adjacentList.end())
                        iter->second.insert(word);
                    else
                    {
                        adjacentList.insert(pair<string,unordered_set<string> >(original,unordered_set<string>()));
                        adjacentList[original].insert(word);
                    }
                }
                word[pos] = beforeChange;
            }
        }
    }

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


       queue<pair<string,int> > wordQueue;
       wordQueue.push(make_pair(start,1));

       unordered_map< string,unordered_set<string> > adjacentList;
       
       string topWord;

       int ans = 1;

       unordered_set<string> visited;
       visited.insert(start);

       while(!wordQueue.empty())
       {
           topWord = wordQueue.front().first;
           
           if(testDistance(topWord,end))
           {
               return wordQueue.front().second+1;
           }
           else
           {
               BuildAdjacentList(topWord,adjacentList,dict);

               auto iter = adjacentList.find(topWord);
               if(iter!= adjacentList.end())
               {
                   for(unordered_set<string>::iterator iterset = iter->second.begin();iterset!= iter->second.end();iterset++)
                   {
                       if(visited.find(*iterset)==visited.end())
                       {
                           wordQueue.push(make_pair(*iterset,wordQueue.front().second+1));
                           visited.insert(*iterset);
                       }
                       
                   }
               }
                
           }
           wordQueue.pop();
       }
       return 0;
   }
};


    int main()
    {
        Solution *mySolution = new Solution();
         
        unordered_set<string> dict;
        dict.insert("hot");
        //dict.insert("dot");
        dict.insert("dog");
        //dict.insert("lot");
        //dict.insert("log"); 
        string start = "hot";
        string end = "dog";
 
        cout<<mySolution->ladderLength(start,end,dict);
        return 0;
    }

上面的这份代码,终于AC了,果然考察的重点在另一个思路上。其实,也用不着用空间来存储。比如可以使用更精简的代码,如下:

class Solution{
public:
    int ladderLength(string start,string end,unordered_set<string> &dict)
    {
        queue<pair<string ,int > > wordQueue;
        unordered_set<string> visited;
        wordQueue.push(make_pair(start,1));
        visited.insert(start);

        while(!wordQueue.empty())
        {
            string curStr = wordQueue.front().first;
            int curStep = wordQueue.front().second;
            wordQueue.pop();

            for(int i = 0;i<curStr.size();i++)
            {
                string tmp = curStr;
                for(int j = 0;j<26;++j)
                {
                    tmp[i] = j+'a';
                    if(tmp == end)
                        return curStep+1;
                    if(visited.find(tmp) == visited.end() && dict.find(tmp)!=dict.end())
                    {
                        wordQueue.push(make_pair(tmp,curStep+1));
                        visited.insert(tmp);
                    }
                }
            }
        }
        return 0;

    }
};

加油!

 其实,这道题的重点不在于深搜、广搜剪枝之类的。换个角度说的话,dict很大,多次遍历它的话,影响时间,然后换个思路……
原文地址:https://www.cnblogs.com/qingcheng/p/3404180.html