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.

题意:

    已知两个单词(起始单词和结束单词),一个单词词典,根据转换规则计算从起始单词到结束单词的所有最短转换路径。

转换规则如下:

    1.转换时,只能转换单词中的1个字符。

    2.转换得到的新单词,必须在单词词典中。

需要注意的是:

    1.若无法转换到endWord,返回0。

    2.所有单词长度相同。

    3.只包含小写字符。

    4.wordList中的无重复单词。

    5.beginWord和endWord非空且不相同。

思考:

    1.在宽度优先搜索时,如何保存搜索时的路径?

    在宽度优先搜索中,将普通队列更换为vector实现,保存所有的搜索节点,即在pop节点时不会丢弃队头元素,只是移动front指针。在队列节点中,增加该节点的前驱节点的在队列中的下标,可通过该下标找到从哪个节点搜索到当前节点。

                                             

2.如果起始点与终点之间有多条路径,如何将多条路径全部搜索出?

    到达某一位置可能有多条路径,使用映射记录到达每个位置的最短需要的步数,新扩展到的位置只要“未曾到达”或者“到达步数与最短步数相同”,即将该位置添加到队列中,从而存储了从不同前驱到达该位置的情况。

    

                                 

 

代码如下:

class Solution {
private:
   struct Node
    {
        std::string mWord;
        int mParentPos;
        int mStep;
        Node(std::string word, int parentPos, int step) :
            mWord(word), mParentPos(parentPos), mStep(step) {}
    };
    bool IsLadder(const string& firstWord, const string& secondWord)
    {
        int count = 0;
        for (int i = 0; i < firstWord.size(); i++)
        {
            if (firstWord[i] != secondWord[i])
            {
                count++;
            }
        }
        return count == 1;
    }

    void ConstructGraph(const string& beginWord, vector<string>& wordList, map<string, vector<string>>& graph)
    {
        bool hasBeginWord = false;
        for (int i = 0; i < wordList.size(); i++)
        {
            if (wordList[i] == beginWord)
            {
                hasBeginWord = true;
            }
        }

        if (!hasBeginWord)
            wordList.push_back(beginWord);

        for (int i = 0; i < wordList.size(); i++)
        {
            for (int j = i + 1; j < wordList.size(); j++)
            {
                if (IsLadder(wordList[i], wordList[j]))
                {
                    graph[wordList[i]].push_back(wordList[j]);
                    graph[wordList[j]].push_back(wordList[i]);
                }
            }
        }
    }
    
public:
    vector<vector<string>> findLadders(string beginWord, string endWord, vector<string>& wordList) {
       vector<Node> log;
        map<string, int> visited;
        map<string, vector<string>> graph;
        vector<int> endWordPostion;
        ConstructGraph(beginWord, wordList, graph);
        visited[beginWord] = 1;
        log.push_back(Node(beginWord, -1, 1));
        int minCount = 0;  //到达endWord的最小步数
        int front = 0;    //模拟队列头指针
        while (front != log.size())
        {
            string word = log[front].mWord;
            int count = log[front].mStep;

            if (minCount != 0 && count > minCount) //所有到终点的路径都搜索完成
            {
                break;
            }
            if (word == endWord)    //搜索到终点时,记录到达终点的最小步数
            {
                minCount = count;
                endWordPostion.push_back(front);
            }

            for (int i = 0; i < graph[word].size(); i++)
            {
                if (visited.find(graph[word][i]) == visited.end() ||
                    visited[graph[word][i]] == count + 1)
                {
                    log.push_back(Node(graph[word][i], front, count + 1));
                    visited[graph[word][i]] = count + 1;
                }
            }
            front++;
        }

        //计算最终路径
        vector<vector<string>> result;
        for (int i = 0; i < endWordPostion.size(); i++)
        {
            int pos = endWordPostion[i];
            vector<string> path;
            while (pos != -1)
            {
                path.push_back(log[pos].mWord);
                pos = log[pos].mParentPos;
            }

            result.push_back(vector<string>());
            for (int j = path.size() - 1; j >= 0; j--)
            {
                result[i].push_back(path[j]);
            }
        }
        return result;
    }
    
};


 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值