LeetCode | Word Ladder II

题目:

Given two words (start and end), and a dictionary, find all shortest transformation sequence(s) 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"]

Return

  [
    ["hit","hot","dot","dog","cog"],
    ["hit","hot","lot","log","cog"]
  ]

Note:

  • All words have the same length.
  • All words contain only lowercase alphabetic characters.

思路:

陷阱比较多的一道题目。最基本的思路是dijkstra算法。但是空间与时间复杂度较高。更好的思路是BFS,但是要注意几个问题:
1)上一层可能有多个结点指向下一层,因此可以产生多个路径。如下图B->E,C->E。
2)尽管上一层有多个结点指向本层一个结点,但是在BFS的时候该结点只需要遍历一次。访问B或者C时,程序都会尝试将E放入BFS的queue。
3)对于空间的优化:
 1- dict可能很大,建议直接使用而不是复制到class中
 2- 输出结果的保存,直接用vector存储这个结点链需要大量的空间开销。我采用的方法是一个字符串对pair<string, string>。第一个字符串代表子节点的字符串,第二个字符串代表父节点的字符串。因此从end出发递归可以求出整个结点链。
 3- queue要保存需要访问的结点,并且还需要存储结点的层级。我采用的方式是两个queue,一个保存上一层级的已经访问的结点,另一个保存下一层级需要访问的结点。
 4- 需要判断某个结点是否已经出现在queue中,因此queue采用set保存比较合适。
 5- 遍历一个层次的结点后将这个层次的结点删除,防止字符串变形反向进行。


《LeetCode | Word Ladder II》



代码:

class Solution {
public:
    vector<string> path;
    unordered_multimap<string, string> childToParent;
    vector<vector<string>> results;
    int level;
    
    vector<vector<string>> findLadders(string start, string end, unordered_set<string> &dict) {
        set<string> nodes[2];
        nodes[1].insert(start);
        
        pair<string,string> ctp (start,"");
        childToParent.insert(ctp);
        
        removeItem(end,dict);
        level=0;
        
        while(!nodes[0].empty()||!nodes[1].empty())
        {
            if(nodes[level%2].empty())
            {
                level+=1;
                for(set<string>::iterator p=nodes[level%2].begin();p!=nodes[level%2].end();p++)
                {
                    removeItem(*p,dict);
                }
            }
            
            set<string>::iterator ptr = nodes[level%2].begin();
            string cur = *ptr;
            nodes[level%2].erase(ptr);
            
            if(cur==end)
            {
                break;
            }

            string next = cur;
            next = changeStr(cur, next, end, dict);
            
            while(next!="")
            {
                pair<string,string> ctp (next,cur);
                childToParent.insert(ctp);
                set<string>::iterator ptr = nodes[(level+1)%2].find(next);
                if(ptr==nodes[(level+1)%2].end())
                    nodes[(level+1)%2].insert(next);
                next = changeStr(cur, next, end, dict);
            };
        };

        getPath(end, start, 1);
        return results;
    }
    
    string changeStr(string current, string begin, string target, unordered_set<string> &dict)
    {
        int s=0;
        int l=0;
        if(begin!=current)
        {
            for(;s < current.size();s++)
            {
                if(current[s] != begin[s])
                {
                    break;
                }
            }
            l = begin[s]-'a'+1;
        }
        if(l==26)
        {
            s++;
            l=0;
        }
        for(int i=s;i<current.size();i++)
        {
            for(int j=(i==s)?l:0;j<26;j++)
            {
                if(current[i]!='a'+j)
                {
                    string tmp = current;
                    tmp[i] = 'a'+j;
                    if(tmp==target)
                    {
                       return tmp;
                    }
                    else
                    {
                        if(findItem(tmp,dict))
                        {
                            return tmp;
                        }
                    }
                }
            }
        } 
        return "";
    }
    
    void getPath(string str, string start, int pathLen)
    {
        if(str == start)
        {
            if(pathLen==level)
            {
                vector<string> r;
                r.push_back(str);
                for(int i=path.size()-1;i>=0;i--)
                {
                    r.push_back(path[i]);
                }
                results.push_back(r);
            }
        }
        else
        {
            pair<unordered_multimap<string, string>::iterator,unordered_multimap<string,string>::iterator > range = childToParent.equal_range(str);
            for(unordered_multimap<string, string>::iterator ptr=range.first;ptr!=range.second;ptr++)
            {
               path.push_back(ptr->first);
               getPath(ptr->second, start, pathLen+1);
               path.pop_back();
            }
         }
    }
    
    bool haveItem(string str)
    {
        unordered_multimap<string,string>::const_iterator got = childToParent.find(str);
        if ( got == childToParent.end() )
            return false;
        else
            return true;
    }
    
    string getParent(string str)
    {
        unordered_multimap<string,string>::const_iterator got = childToParent.find(str);

        if ( got == childToParent.end() )
            return NULL;
        else
            return got->second;
    }
    
    void removeItem(string s, unordered_set<string> &dict)
    {
        unordered_set<string>::const_iterator p = dict.find(s);
        while(p!=dict.end())
        {
             dict.erase(p);
             p = dict.find(s);
        };
    }
    
    bool findItem(string s, unordered_set<string> &dict)
    {
        unordered_set<string>::const_iterator p = dict.find(s);
        if(p!=dict.end())
        {
            return true;
        }
        else
        {
            return false;
        }
        
    }
};
    原文作者:Allanxl
    原文地址: https://blog.csdn.net/lanxu_yy/article/details/17788805
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞