Leetcode 126. Word Ladder II

  • 126. Word Ladder II
    • 题目
    • 题目解析
    • 基于广度优先的改进方法

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:

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.

Input:
beginWord = "hit",
endWord = "cog",
wordList = ["hot","dot","dog","lot","log","cog"]

Output:
[
  ["hit","hot","dot","dog","cog"],
  ["hit","hot","lot","log","cog"]
]

题目解析

题目的意思是给定一个起点和一个终点单词,中间单词全部在给定的集合中,每次可以更改一个字母,求到达终点单词的最短路径。这里有几个细节:
1. 终点单词必须在给定的集合中
2. 路径可能是多条

可以很明显的看出这是一个最短路径的搜索问题,大概有两种思路:
1. 控制深度的深度搜索
2. 广度优先搜索

最开始想到的办法是先用广度优先搜索获得最短的路径长度,然后用这个路径长度控制深度优先的深度,来构建路径。因为最终需要得到的是路径,因此无论如何都需要用深度优先来构建路径。这样大概分为以下几步:
1. 对单词建图,对于每两个单词,如果只有一个字母不同,说明存在一条路径
2. 进行广度优先搜索,按层搜索,得到最短的路径长度
3. 进行深度搜索,控制深度,构建路径

但这样写下来的时候,直接第一步建图就超时了,无法通过。

基于广度优先的改进方法

然后参考网上思路,直接建图会超时,因为可能中间节点过多。由于只有26个字母,改为搜索每个字母的空间,搜索的空间只与单词长度有关,这样就不会超时,但后面写的搜索仍然超时。考虑可能是有一些重复工作,考虑在广度优先的时候,其实已经进行分层了,只是没记录路径,如果我们使用一个哈希记录广度搜索时每个节点的扩展节点,然后按层来构建的话,这样的深度搜索只是起到构建结果的作用,复杂度大大降低,代码如下:

class Solution {
public:
    vector<string> v;
    // 深度优先搜索构建
    void solve(string beginWord, string endWord,unordered_map<string, vector<string> >& us,vector<vector<string> > &vvs)
    {
        v.push_back(beginWord);
        if (beginWord == endWord)
        {
            vvs.push_back(v);
            return;
        }
        for (int i = 0; i < us[beginWord].size(); i++)
        {
            solve(us[beginWord][i], endWord, us, vvs);
            v.pop_back();
        }
    }
    vector<vector<string>> findLadders(string beginWord, string endWord, vector<string>& wordList) {
        vector<vector<string> > vvs;
        unordered_set<string> us;
        for (int i = 0; i < wordList.size(); i++)
            us.insert(wordList[i]);
        if (!us.count(endWord))
            return vvs;
        // 去除重复元素
        if (us.count(beginWord))
            us.erase(beginWord);
        unordered_map<string, vector<string> > usv;
        unordered_set<string> current;
        current.insert(beginWord);
        unordered_set<string> next;
        bool f = false;
        int count = 1;
        while (current.size()>0)
        {
            if (f)
                break;
            for (auto it:current)
            {               
                vector<string> vs;
                // 搜索下一层的,直接搜索字母空间,复杂度时O(n*26)
                for (int i = 0; i < beginWord.size(); i++)
                {
                    string tmp = it;
                    for (char a = 'a'; a <= 'z'; a++)
                    {
                        tmp[i] = a;
                        if (us.count(tmp))
                        {
                            next.insert(tmp);
                            vs.push_back(tmp);
                            if (tmp == endWord)
                                f = true;
                        }
                    }
                }
                usv[it] = vs;
            }
            // 一层遍历完删除已经遍历的
            for (auto it :next)
                us.erase(it);
            current = next;
            next.clear();
            count++;  // 深度
        }
        if (!f)
            return vvs;
        solve(beginWord, endWord, usv,vvs);
        return vvs;
    }
};

如有错误,欢迎指正~

你可能感兴趣的:(Leetcode)