leetcode 题解:Word Ladder 2(单词接龙 2)

Given two words (beginWord and endWord), and a dictionary’s word list, find all shortest transformation sequence(s) from beginWord to endWord, such that:(给定两个单词(beginWord 和 endWord)和一个字典 wordList,找出所有从 beginWord 到 endWord 的最短转换序列。转换需遵循如下规则

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.

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

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.
endWord “cog” 不在字典中,所以不存在符合要求的转换序列。

题解:和 word ladder 1 一样,是一个图的问题,采用BFS (广度优先搜索)方法求解。

难点1: 将关联关系的图构建出来。

因为改变过程中的所有单词都在字典里面,可以对字典循环,将每次可能改变的字符的位置设为* 构建一个Map (如下图代码所示. 对于example 1 来说:workList[*ot] = {“hot”, “dot”, “lot”};

        unordered_map<string, vector<string>> wordMap;
            for(int i=0;i<wordList.size();i++)
            {
                    string word = wordList[i];
                    for(int j=0;j<word.size();j++)
                    {
                            string temp = word;
                            temp[j]='*';
                            wordMap[temp].push_back(word);
                    }
            }

难点2:记录路径:
与word ladder1 不同,这次需要将路径输出,而不仅仅是一个最小节点个数。所以队列的元素需要包含路径信息,定义为"queue<pair<string, vector>> q" 其中 vector 就是来记录路径的

难点3:某些节点需要重复访问:
不能使用bool值来标记节点是否访问过,因为有一些节点有可能需要重复访问,例如: hit->hot->dot->lot->log->cog,这条路径虽然不是最短的,但是访问了lot节点,如果将此节点标记,会导致hit->hot->lot->log->cog这个最短路径找不到,所以用一个名为cost 的 map来记录每个节点访问的路径长度,如果比cost小,则需要重新访问该节点。

            for(int i=0;i<wordList.size();i++)
            {
                    cost[wordList[i]] = INT_MAX;
            }
                    for(int j=0;j<curString.size();j++)
                    {
                            string temp = curString;
                            temp[j] = '*';

                            if(wordMap.find(temp)!=wordMap.end())
                            {
                                vector<string> nextV;
                                nextV = wordMap[temp]; 
                                for(int i=0;i<nextV.size();i++)
                                {
                                        string next = nextV[i];
                                      if(curPath.size()<cost[next]){
                                              curPath.push_back(next);
                                              q.push(make_pair(next, curPath));
                                              cost[next] = curPath.size();
                                              curPath.pop_back();  
                                      }
                                        
                                }
                            }

                    }

难点4: 判断最短路径:
到达终点的路径有很多,但是我们只需要最短的,并且不止是一条最短的路径。在此定义一个minCount, 初始设为最大值, 来记录最短路径的节点数,第一个到达终点的,一定是最短的,要将其记录下来,后面就判断如果有其他路径的节点个数也等于minCount, 就把它放在最终的结果里面。

                    if(curString == endWord)
                    {
                            if(minCount==INT_MAX) minCount = curPath.size();
                            if(minCount!=INT_MAX)
                            {
                                    if(curPath.size() == minCount) {
                                            results.push_back(curPath);
                                    }
                            }
                    }

最终代码:

class Solution {
public:
    vector<vector<string>> findLadders(string beginWord, string endWord, vector<string>& wordList) {
        unordered_map<string, vector<string>> wordMap;
            for(int i=0;i<wordList.size();i++)
            {
                    string word = wordList[i];
                    for(int j=0;j<word.size();j++)
                    {
                            string temp = word;
                            temp[j]='*';
                            wordMap[temp].push_back(word);
                    }
            }
            vector<vector<string>> results;
            queue<pair<string, vector<string>>> q;
            vector<string> path;
            path.push_back(beginWord);
            q.push(make_pair(beginWord, path));
            unordered_map<string, int> cost;
            for(int i=0;i<wordList.size();i++)
            {
                    cost[wordList[i]] = INT_MAX;
            }
            int minCount = INT_MAX;
            while(!q.empty())
            {
                    pair<string,vector<string>> curPair = q.front();
                    q.pop();
                    string curString = curPair.first;
                    vector<string> curPath = curPair.second;
                    if(curString == endWord)
                    {
                            if(minCount==INT_MAX) minCount = curPath.size();
                            if(minCount!=INT_MAX)
                            {
                                    if(curPath.size() == minCount) {
                                            results.push_back(curPath);
                                    }
                            }
                    }
                    

                    for(int j=0;j<curString.size();j++)
                    {
                            string temp = curString;
                            temp[j] = '*';

                            if(wordMap.find(temp)!=wordMap.end())
                            {
                                vector<string> nextV;
                                nextV = wordMap[temp]; 
                                for(int i=0;i<nextV.size();i++)
                                {
                                        string next = nextV[i];
                                      if(curPath.size()<cost[next]){
                                              curPath.push_back(next);
                                              q.push(make_pair(next, curPath));
                                              cost[next] = curPath.size();
                                              curPath.pop_back();  
                                      }
                                        
                                }
                            }

                    }
                    
            }
            return results;
 
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值