Leetcode(W5):126. Word Ladder II

前言:这道题相比上一道要更加困难,因此也要想办法改进算法。


1. 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:
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.word.

题意:

与上一道题目一样,只不过上一道题目是求出最短路径长度就够了,这道题则是要把所有的最短路径罗列出来。

举例:

beginWord = “hit”
endWord = “cog”
wordList = {“hot”,”dot”,”dog”,”lot”,”log”,”cog”}
返回:
[
[“hit”,”hot”,”dot”,”dog”,”cog”],
[“hit”,”hot”,”lot”,”log”,”cog”]
]

思路:

仍然是用BFS,注意这次返回的是二重vector迭代器,第二层迭代里面是单纯的字符串,所以不能再使用pair了,并且pair来记录步数也十分的麻烦。
仍然按照上一道题目的思路,先把起点beginWord装进vector中,再把这个vector装进队列paths中,队列中每一个vector都是一条路径,我们要做的就是每次都从paths里面取出一个vector,然后根据这个vector最后一个节点来检索下一步的走法(仍然用上一道题一样的字母替换法),检索完毕后将新的路径装到vector后面,然后再把vector入列,直到找到所有最短路径。
不过这样是很容易TLE的。我们需要一个currentlen变量来记录当前走的步数以及minlen变量来记录最短路径的长度。设想一种中间情况我们处理的vector容量已经到4了,也就是现在已经走了4步了,currentlen为4,那么我们在走第5步的时候发现了终点,minlen于是更新为5,此时队列的vector容量分别有4(正在处理这个),4,4,5,5,5,5……,在已知最短路径为5 的情况下,我们只需要把接下来两个4处理了看还能不能找到最短路径即可,后面的5就不用处理了,因为就算能到终点也不是最短路径了,这就是剪枝。
还有,上一道题我们每走一步,就从原图中把这一步给删除掉,而这道题要求的是最短路径的集合,如图:
这里写图片描述
如果在检索红4能走的路径的时候,走到蓝5然后把蓝5删掉了,那么接下来黄4这条路就断了,所以我们在4的话就必须等所有的4都处理完才能删除走过的节点,也就是这个蓝5。

操作:

都在代码注释了。

2. 代码

class Solution {
public:
    vector<vector<string>> findLadders(string beginWord, string endWord, vector<string>& wordList) {
        int currentlen = 1, minlen = INT_MAX;//前者是当前探查的路径长度,后者是已知的最短路径长度。
        vector<vector<string>> result;
        queue<vector<string>> paths;//存放所有的路径
        vector<string> p{ beginWord };//所有路径的起始点
        paths.push(p);
        set<string> wordlist(wordList.begin(), wordList.end());
        set<string> chongfuwords;//记录每次新添加的节点,这些节点在新的一轮路径搜索中要从原图去掉。
        while (!paths.empty())
        {
            auto currentpath = paths.front();
            paths.pop();
            if (currentpath.size() > currentlen) {//如果大于,说明现在探查已经进入“下一轮”了
                for (string str : chongfuwords) {//这个时候才是利用完毕新节点,把它们从原图删掉。防止路径探查往回走,出现死循环
                    wordlist.erase(str);
                }
                chongfuwords.clear();//清空上一轮的节点,准备下一轮。
                currentlen = currentpath.size();//更新此轮的路径长度
                if (currentlen >= minlen) 
                    break;//如果此轮的路径长度已经大于等于最短路径,那么以后每一轮的长度都只会比最短路径更大,所以不用再检索了,游戏结束
            }
            string lastnode = currentpath.back();//取出当前路径最后的一个节点,开始检索这个节点后面存在的路径
            for (int i = 0; i< lastnode.size(); i++)
            {
                string str = lastnode;//注意每一轮i循环都是下标跳到下一位。要重新给str赋值成原单词
                for (int j = 0; j < 26; j++)
                {
                    str[i] = 'a' + j;//每次修改一位,将这一位从a到z遍历,修改完后的单词保存在str
                    if (wordlist.find(str) != wordlist.end()) {
                        vector<string> newpath = currentpath;//新的路径得从上一个路径继承,然后尾部添加一个新的节点
                        newpath.push_back(str);
                        if (str == endWord) {//如果恰好尾部节点是终点,就可以添加到结果容器中。
                            result.push_back(newpath);
                            minlen = currentlen;//由于是BFS,所以第一次更新这个值的时候肯定就是最短路径。
                        } else {
                            paths.push(newpath);//如果不是终点,则还需添加到路径队列中继续搜索。
                        }
                        chongfuwords.insert(str);
                        //wordlist.erase(str);//注意:这里不能像上一道题目那样把新找到的节点用一次就删掉,因为后面可能的最短路径也要用到这个节点。
                    }
                }
            }
        }
        return result;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值