126. Word Ladder II

题目描述

Given two words (beginWord and endWord), and a dictionarys word list, find all shortest transformation sequence(s) from beginWord o endWord,
such that:
Only one letter can be changed at a time 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.

方法1

思路

BFS
例如:

{hit} ->
{hit,hot} ->
{hit,hot,dot}/{hit,hot,lot} ->
["hit","hot","dot","dog"]/["hit","hot","lot","log"] ->
["hit","hot","dot","dog","cog"],
["hit","hot","lot","log","cog"]

代码实现

class Solution {
public:
    vector<vector<string>> findLadders(string beginWord, string endWord, vector<string>& wordList) {
         
        unordered_set<string> dict(wordList.begin(),wordList.end());
        if(dict.find(endWord) == dict.end()) 
            return {};
        vector<vector<string>> ret;
        //队列中保存的是到当前层的所有的路径
        queue<vector<string>> q;
        q.push({beginWord});
        dict.erase(beginWord);
        unordered_set<string> nextLevel;
        bool success= false;
        while(!q.empty())
        {
            int n= q.size();
            while(n--)
            {   
                vector<string> cur = q.front();
                q.pop();
                string word = cur.back();
                if(canTransformed(word, endWord))
                {
                	cur.push_back(endWord);  
                    success=true;
                    ret.push_back(cur);
                }
                else
                {
                	if(success)
                		continue;
                    for(int i = 0; i < word.size(); ++i) 
                    {
                    	string next = word;
                        for(char c = 'a'; c <= 'z'; ++c) 
                        {
                        	next[i] = c;
                            if(dict.find(next)!=dict.end())
                            {
                            	nextLevel.insert(next);
                                vector<string> temp = cur;
                                temp.push_back(next);
                                q.push(temp);           
                            } 
                        } 
                    }                    
                }
            }
            if(success) 
            	break;  
            //在每一层完全操作完成之后,才统一的在字典中消除已经用过
            //的单词,是因为同一层的两个不同的单词可以转换为下一层相同的
            //的单词,而我们这里求的是所有的路径,而不是能否
            for(auto elem:nextLevel)
                dict.erase(elem); 
            nextLevel.clear();
        }
        return ret;
    }    
    bool canTransformed(const string &s,const string &str)
    {

        int cnt=0;
        for(int i=0;i<s.length();++i)
        {
            if(s[i]!=str[i])
            	++cnt;
        }
        return (cnt==1)?true:false;
    }
};

方法2

思路

传统的BFS+DFS
一个节点,不能位于不同的层,一个节点如果在前面的层已经出现过了,那么它在后面的层就不能再出现了。为了使每一层加入的结点唯一不与前面已经加入的节点产生重复,并且在加入结点过程中获得层与层之间的结点邻接关系,维护一个已经加入的结点所处于的层的信息,每加入一层的
结点,更新层与层之间的邻接关系表,(curNode,nextNodeList)

代码实现

class Solution {
public:
	vector<vector<string>> findLadders(string beginWord, string endWord, vector<string>& wordList)
	{
		unordered_set<string> dict(wordList.begin(),wordList.end());
        if(dict.find(endWord) == dict.end()) 
            return {};
        unordered_map<string, vector<string>> nextNodeList;
        //已经遍历到的结点所处于的层次
        unordered_map<string,int> level;
		queue<string> q;
		q.push(beginWord);
	    level[beginWord] = 1;
		bool success = false;
		while(!q.empty())
		{
			int n = q.size();
			while(n--)
			{
				string cur = q.front();
			    q.pop();
			    for(int i = 0; i < cur.size(); i++)
			    {
			    	string next = cur;
				    for(char c = 'a'; c <= 'z'; c++)
				    {
				    	next[i] = c;
					    if(dict.find(next) != dict.end())
					    {   //产生的下一层的新的结点
					    	if(level.find(next) == level.end())
						    {
						    	if(next == endWord)
						    		success = true;
						    	q.push(next);
							    level[next] = level[cur] + 1;
							    nextNodeList[cur].push_back(next);
						    }
                            //说明这个节点也能到达下一层一个其他节点
                            //能够到达的节点
						    else if(level[next] == level[cur]+1)
						    	nextNodeList[cur].push_back(next);  
					    }
				    }
				}
			}
			if(success)
				break;
		}

		if(!success)
        	return {};
        vector<vector<string>> ret;
        vector<string> temp;
        temp.push_back(beginWord);
        dfs(nextNodeList,beginWord,endWord,ret,temp);        
        return ret;
	}
    //注意这种dfs,递归函数的参数携带到达当前位置的路径值,函数
    //返回值为void
	void dfs(unordered_map<string, vector<string>> &nextNodeList,string beginWord,string endWord,vector<vector<string>> &ret,vector<string> &temp)
    {
        if(beginWord == endWord)
        {
            ret.push_back(temp);
            return;
        }
        //枚举当前位置能到达的所有情况
        for(auto item : nextNodeList[beginWord]) 
        {
            temp.push_back(item);
            dfs(nextNodeList,item,endWord,ret,temp);
            //为了保证在递归过程中参数的一致性,保持递归参数
            //在开始和结束时的状态不变
            temp.pop_back();
        }
    }
};

方法3

思路

两端同时bfs
两端最优一定会全局最优,因为最终的最优路径一定是确定的,而我们是从两头往中间扫,直到相遇,这期间无论我们将节点分到正向队列,还是反向队列中,都不影响nextList的连接关系。

代码实现

class Solution {   
public:
	vector<vector<string>> findLadders(string beginWord, string endWord, vector<string>& wordList) 
    {
    	
    	unordered_set<string> dict(wordList.begin(),wordList.end());
        if(dict.find(endWord) == dict.end()) 
            return {};
        //
        unordered_map<string, vector<string>> nextNodeList;
        //因为可能出现同一层的两个不同节点到达下一层的同一个节点
        //为了避免重复,这里正反向每一层都使用一个集合存储
        unordered_set<string> q[2] = {{beginWord},{endWord}};
        bool success = false;
        dict.erase(beginWord);//这个节点已经使用过了 
        dict.erase(endWord);//这个节点已经使用过了
        int cur = 0;
        while(!q[cur].empty() && !q[1-cur].empty())
        {
        	if(q[cur].size() > q[1-cur].size())
        		cur = 1-cur;
            unordered_set<string> nextLevel;
            for (auto item : q[cur])
            {
                for (int l = 0; l < item.size(); ++l) 
                {
                	auto next = item;
                    for (char c = 'a'; c <= 'z'; ++c)
                    {	
                        next[l] = c;
                        if(q[1-cur].find(next) != q[1-cur].end()) 
                        {
                            if(cur == 0) 
                            	nextNodeList[item].push_back(next);
                            else 
                            	nextNodeList[next].push_back(item);
                            success = true;
                        }
                        else if(dict.find(next) != dict.end())
                        {
                            nextLevel.insert(next);
                            if(cur == 0) 
                            	nextNodeList[item].push_back(next);
                            else 
                            	nextNodeList[next].push_back(item);
                        }
                    }
                }
            }
            if(success)
            	break;
            for(auto item : nextLevel)
                dict.erase(item); 
            q[cur] = nextLevel;
            cur = 1-cur;
        } 

        if(!success)
        	return {};
        vector<vector<string>> ret;
        vector<string> temp;
        temp.push_back(beginWord);
        dfs(nextNodeList,beginWord,endWord,ret,temp);        
        return ret;
    }

    void dfs(unordered_map<string, vector<string>> &nextNodeList,string beginWord,string endWord,vector<vector<string>> &ret,vector<string> &temp)
    {
        if(beginWord == endWord)
        {
            ret.push_back(temp);
            return;
        }
        for(auto item : nextNodeList[beginWord]) 
        {
            temp.push_back(item);
            dfs(nextNodeList,item,endWord,ret,temp);
            temp.pop_back();
        }
    }
};

posted on 2021-05-02 19:41  朴素贝叶斯  阅读(38)  评论(0编辑  收藏  举报

导航