leetcode 126. Word Ladder II

Given two words (beginWord and endWord), and a dictionary's word list, find all shortest transformation sequence(s) from beginWord to endWord, such that:

  1. Only one letter can be changed at a time
  2. Each transformed word must exist in the word list. Note that beginWord is not a transformed word.

Note:

  • Return an empty list if there is no such transformation sequence.
  • All words have the same length.
  • All words contain only lowercase alphabetic characters.
  • You may assume no duplicates in the word list.
  • You may assume beginWord and endWord are non-empty and are not the same.

Example 1:

Input:
beginWord = "hit",
endWord = "cog",
wordList = ["hot","dot","dog","lot","log","cog"]

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

Example 2:

Input:
beginWord = "hit"
endWord = "cog"
wordList = ["hot","dot","dog","lot","log"]

Output: []

Explanation: The endWord "cog" is not in wordList, therefore no possible transformation.

 

给定两个单词(beginWord 和 endWord)和一个字典 wordList,找出所有从 beginWord 到 endWord 的最短转换序列。转换需遵循如下规则:

每次转换只能改变一个字母。
转换过程中的中间单词必须是字典中的单词。
说明:

如果不存在这样的转换序列,返回一个空列表。
所有单词具有相同的长度。
所有单词只由小写字母组成。
字典中不存在重复的单词。
你可以假设 beginWord 和 endWord 是非空的,且二者不相同。
示例 1:

输入:
beginWord = "hit",
endWord = "cog",
wordList = ["hot","dot","dog","lot","log","cog"]

输出:
[
  ["hit","hot","dot","dog","cog"],
  ["hit","hot","lot","log","cog"]
]
示例 2:

输入:
beginWord = "hit"
endWord = "cog"
wordList = ["hot","dot","dog","lot","log"]

输出: []

解释: endWord "cog" 不在字典中,所以不存在符合要求的转换序列。

 

解题思路:

一开始我以为是列出所有可能路径,所以想用深度优先搜索来做,后来发现是求所有最短路径,尽管保存了每个字符串的路径深度,但是没有办法保证第一条发现的路径深度就是最短路径深度,而且删掉原来的路径也非常麻烦。但是因为广度优先搜索是层层搜索的,所以可以保证第一条发现的路径深度是最短路径深度,之后的无效路径不用加入就行了。

广度优先搜索模板:

queue<type> q ;
q.push(beginnode);
while(!q.empty())
{
    for(int sz = q.size() ; sz > 0 ; sz--)
    {
        type p = q.front() ;
        q.pop() ;
        对q做一系列处理 ; 
        q.push(child_of_q)(终止条件,也就是什么时候不再往queue中加子节点) ;
    }
}
class Solution {
public:
    vector<vector<string>> findLadders(string beginWord, string endWord, vector<string>& wordList) 
    {        
        unordered_set<string> dict(wordList.begin() , wordList.end()) ;    
        if(dict.empty() || !dict.count(endWord)) return {} ;
        dict.erase(beginWord) ;
        dict.erase(endWord) ;
        
        unordered_map<string , int> steps = {{beginWord , 1}} ; // 每个字符串最短的路径深度
        unordered_map<string , vector<string> > parents ; //每个字符串的母节点
        queue<string> q ; //每层的节点集合 。
        q.push(beginWord) ;
        bool found = false ;
        int step = 0 ;
        
        //将所有有效路径加入图中
        while(!q.empty() && !found)
        {
            step++ ; //层序号
            for(int sz = q.size() ; sz > 0 ; sz--) //遍历每层的节点
            {
                string p = q.front() ; 
                string w = p ;
                q.pop() ;
                
                for(int i = 0 ; i < p.size() ; i++)  //遍历每个节点所有子节点
                {
                    char ch = w[i] ;
                    for(char j = 'a' ; j <= 'z' ; j++)
                    {
                        if(j == w[i]) continue ;
                        w[i] = j ;
                        if(w == endWord) 
                        {
                            parents[w].push_back(p) ;
                            found = true ;
                        }
                        else if(steps.count(w) && step < steps[w]) // 当当前层序小于字符串所在层序,该路径才有效,才将当前节点记作其父节点,否则路径无效,不加入图中。
                        {
                            parents[w].push_back(p) ;
                        }
                        
                        if(!dict.count(w)) continue ;
                        
                        dict.erase(w) ;  //当遍历到该字符串时,将当前节点记作其父节点,从字典中删去,避免陷入环。
                        q.push(w) ;
                        steps[w] = steps[p] + 1 ;
                        parents[w].push_back(p) ;
                        
                    }
                    w[i] = ch ;
                }
            }
        }
        
        //从后往前深度优先搜索,将所有可能路径加入ans中。
        if(found)
        {
            vector<string> result = { endWord } ;  // 向量初始化
            get(endWord , beginWord , parents , result ) ;
        }
            
        
        return ans ;
    }
    
private :
    
    vector<vector<string> > ans ;
    
    void get(string child , string beginWord , unordered_map<string , vector<string> >parents , vector<string> result )
    {
        for(string s : parents[child])
        {
            if(s == beginWord)
            {
                result.push_back(s) ;
                ans.push_back(vector<string>(result.rbegin() , result.rend())) ;
                return ;
            }
            else
            {
                result.push_back(s) ;
                get(s , beginWord , parents , result) ;
                result.pop_back() ;
            }
        }
    }
    
};
class Solution {
public:
    vector<vector<string>> findLadders(string beginWord, string endWord, vector<string>& wordList) 
    {
        unordered_set<string> dict(wordList.begin() , wordList.end()) ;
        if(!dict.count(endWord)) return {} ;
        dict.erase(beginWord) ;
        dict.erase(endWord) ;
        
        unordered_map<string , int> steps = {{beginWord , 1}} ;
        unordered_map<string , vector<string>> parents ;
        queue<string> q ;
        q.push(beginWord) ;
        int step = 0 ;
        bool found = false ;
        
        while(!q.empty())
        {
            step++ ;
            cout<<"step:"<<step<<endl;
            //cout<<"qz:"<<q.size()<<endl;
            for(int i = q.size() - 1 ; i >= 0 ; --i)
            {
                cout<<"i:"<<i<<endl;
                string s = q.front() , w = s ;
                q.pop() ;
                for(int j = 0 ; j < s.size() ; ++j)
                {
                    //cout<<"j:"<<j<<endl;
                    char ch = w[j] ;
                    for(char k = 'a' ; k <= 'z' ; ++k)
                    {
                        if(k == ch) continue ;
                        //cout<<"k:"<<k<<endl;
                        w[j] = k ;
                        if(w == endWord)
                        {
                            //steps[endWord] = step + 1 ;
                            parents[endWord].push_back(s) ;
                            found = true ;
                            break ;
                        }
                        else if(steps.count(w) && step < steps[w])
                        {
                            parents[w].push_back(s) ;
                        }
                        
                        if(!dict.count(w)) continue; 
                        dict.erase(w) ;
                        q.push(w) ;
                        parents[w].push_back(s) ;
                        steps[w] = step + 1 ;
                        
                    }
                    w[j] = ch ;
                    //if(found) break ;//这里不能加found的判断,因为如果同一层的下一个节点第一个字母无法变出dict中的字符串时,会直接跳出,不会去改变第二个字母;"red","tax",["ted","tex","red","tax","tad","den","rex","pee"]
                }
                
            }
            if(found) break ;
        }
        
        //cout<<found<<endl;
        vector<string> result = {endWord} ;
        if(found) get(endWord , beginWord , parents , result) ;
        
        return res ;
    }
    
private :
    vector<vector<string> > res ;
    
    void get(string endWord , string beginWord , unordered_map<string , vector<string>>& parents , vector<string> result)
    {
        for(string s : parents[endWord])
        {
            result.push_back(s) ;
            if(s == beginWord)
            {
                res.push_back(vector<string>(result.rbegin() , result.rend())) ;
                return ;
            }
            get(s , beginWord , parents , result) ;
            result.pop_back() ;
        }
    }
};

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值