126. Word Ladder II(C++实现)

0. 题目描述

此题延续127Word Ladder I ,区别在于,127只需要返回最短路径的步数,而本题目需要返回所有最短路径的路径信息。本文给出两种采用广度优先遍历的方法。

示例1:
Input:
beginWord = "hit",
endWord = "cog",
wordList = ["hot","dot","dog","lot","log","cog"]
Output: [   ["hit","hot","dot","dog","cog"],    ["hit","hot","lot","log","cog"] ]
示例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.直接方法

直接在Word Ladder I 的基础上稍微改动,每次queue中保存路径信息而非步数step信息
此方法,很直接,由于频繁的创建和复制数组,导致时间开销很大,空间占用也很大,queue中有很多冗余
    vector<vector<string>> findLadders(string beginWord, string endWord, vector<string>& wordList) {
        //首先判断wordList是否包含endWord,否则返回0
        unsigned long stringSize = beginWord.size();
        unordered_set<string> wordSet(wordList.begin(), wordList.end());
        queue<vector<string>*> queue1;

        vector<vector<string>> res;

        vector<string>* beginVector = new vector<string>{beginWord};
        queue1.push(beginVector);
        queue1.push(nullptr); //空指针作为标记
        bool isEnd = false;

        if(wordSet.erase(endWord) == 0) // 如果list中不存在endWord,返回0;
            return vector<vector<string>>();

        while(not queue1.empty()){
            vector<string>* curSequence = queue1.front();
            queue1.pop();
            //遍历一遍当前同样步骤的一组路径
            unordered_set<string> curVisited;
            while(curSequence != nullptr){
                string curNode = curSequence->back();
                for(int i=0; i< stringSize; i++){
                    string nextNode = curNode;
                    for(char c='a'; c<='z'; c++){
                        nextNode[i] = c;
                        if(nextNode == endWord){
                            //此时nextNode就是endNode
                            auto * tmp = new vector<string>(*curSequence);
                            tmp->push_back(nextNode);
                            res.push_back(*tmp);
                            delete tmp;
                            isEnd = true;
                        }
                        if(not isEnd)
                            if(wordSet.find(nextNode) != wordSet.end()){
                                curVisited.insert(nextNode); //存到当前步 遇见的node set中
                                auto * nextSequence = new vector<string>(*curSequence);
                                nextSequence->push_back(nextNode);
                                queue1.push(nextSequence);
                            }
                    }
                }
                curSequence = queue1.front();
                queue1.pop();
            }
            if(not res.empty())
                return res;
            if(curVisited.empty())
                break;
            for(const auto &s: curVisited){
                wordSet.erase(s);
            }
            queue1.push(nullptr);
        }
        return res;
    }

2.进一步优化

将路径信息用一个map存储,map的key为节点字符串,value为该节点的父节点所组成的unordered_set<string>(要用set而非vector是为了防止重复),我们从endWord开始遍历,每次把当前节点追加到下一个节点的父节点set中从后往前找。这样在返回的时候每次push_back可以保证beginWord在数组的最前断。

//使用一个map存储节点连接信息,节省了很多多余的操作,在时间上有很大优化
    vector<vector<string>> findLadders(string beginWord, string endWord, vector<string>& wordList) {
        //首先判断wordList是否包含endWord,否则返回0
        unsigned long stringSize = beginWord.size();
        unordered_set<string> wordSet(wordList.begin(), wordList.end());
        queue<string> searchQueue; //开启一个队列用于建立图
        unordered_map<string, unordered_set<string>* > nodesMap;
        if(wordSet.erase(endWord) == 0) // 如果list中不存在endWord,返回0;
            return vector<vector<string>>();
        searchQueue.push(endWord);
        searchQueue.push(""); //空字符串作为标记
        bool isEnd = false;
        while(not searchQueue.empty()){
            string curNode = searchQueue.front();
            searchQueue.pop();
            //遍历一遍当前同样步骤的一组路径
            unordered_set<string> curVisited;
            while(not curNode.empty()){
                for(int i=0; i< stringSize; i++){
                    string nextNode = curNode;
                    for(char c='a'; c<='z'; c++){
                        nextNode[i] = c;
                        if(nextNode == beginWord){
                            //此时nextNode就是beginNode
                            if(nodesMap.find(beginWord) == nodesMap.end())
                                nodesMap.insert(make_pair(beginWord, new unordered_set<string>()));
                            nodesMap[beginWord]->insert(curNode); //设置endWord的父节点
                            isEnd = true;
                        }
                        if(not isEnd)
                            if(wordSet.find(nextNode) != wordSet.end()){
                                curVisited.insert(nextNode); //存到当前步 遇见的node set中
                                if(nodesMap.find(nextNode) == nodesMap.end())
                                    nodesMap.insert(make_pair(nextNode, new unordered_set<string>()));
                                nodesMap[nextNode]->insert(curNode);
                                searchQueue.push(nextNode);
                            }
                    }
                }
                curNode = searchQueue.front();
                searchQueue.pop();
            }
            if(isEnd)
                return searchPaths(nodesMap, beginWord, endWord);
            if(curVisited.empty())
                break;
            for(const auto &s: curVisited){
                wordSet.erase(s);
            }
            searchQueue.push("");
        }
        return vector<vector<string>>();
    }
    vector<vector<string>> searchPaths(unordered_map<string, unordered_set<string>*>& graphNodes, string beginWord, string endWord){
        vector<vector<string>> res;
        queue<vector<string>> queue1;
        queue1.push(vector<string>{beginWord});
        while(not queue1.empty()){
            vector<string> curVector = queue1.front();
            queue1.pop();
            for(const auto& curParent: *graphNodes.find(curVector.back())->second){
                vector<string> nextStep = curVector;
                nextStep.push_back(curParent);
                if(curParent == endWord){
                    res.emplace_back(nextStep);
                }else
                    queue1.push(nextStep);
            }
        }
        return res;
    }
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值