zoukankan      html  css  js  c++  java
  • 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很大,多次遍历它的话,影响时间,然后换个思路……
  • 相关阅读:
    团队协议
    C++ 多继承和虚继承的内存布局(转)
    轻量级的.Net ORM框架介绍
    EF下CodeFirst、DBFirst与ModelFirst分析
    JDK方式
    JSON
    事务的ACID特性
    数据库查询
    Assets
    内部文件存储
  • 原文地址:https://www.cnblogs.com/qingcheng/p/3404180.html
Copyright © 2011-2022 走看看