126. 单词接龙 II

题目

按字典 wordList 完成从单词 beginWord 到单词 endWord 转化,一个表示此过程的 转换序列 是形式上像 beginWord -> s1 -> s2 -> ... -> sk 这样的单词序列,并满足:

  • 每对相邻的单词之间仅有单个字母不同。
  • 转换过程中的每个单词 si1 <= i <= k)必须是字典 wordList 中的单词。注意,beginWord 不必是字典 wordList 中的单词。
  • sk == endWord

给你两个单词 beginWordendWord ,以及一个字典 wordList 。请你找出并返回所有从 beginWordendWord最短转换序列 ,如果不存在这样的转换序列,返回一个空列表。每个序列都应该以单词列表[beginWord, s1, s2, ..., sk] 的形式返回。

示例 1:

复制代码
输入:beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log","cog"]
输出:[["hit","hot","dot","dog","cog"],["hit","hot","lot","log","cog"]]
解释:存在 2 种最短的转换序列:
"hit" -> "hot" -> "dot" -> "dog" -> "cog"
"hit" -> "hot" -> "lot" -> "log" -> "cog"

示例 2:

复制代码
输入:beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log"]
输出:[]
解释:endWord "cog" 不在字典 wordList 中,所以不存在符合要求的转换序列。

提示:

  • 1 <= beginWord.length <= 5
  • endWord.length == beginWord.length
  • 1 <= wordList.length <= 500
  • wordList[i].length == beginWord.length
  • beginWordendWordwordList[i] 由小写英文字母组成
  • beginWord != endWord
  • wordList 中的所有单词 互不相同

思路

首先把字典存起来方便查找,如果目标单词不在字典里,就直接结束,然后先用广度优先搜索,从起始单词开始,逐层尝试改变每个位置的字母,看新单词是否在字典里。在这个过程中,把已用过的单词从字典去掉,避免重复,同时,构建一个反向图,记录每个符合条件的新单词是由哪个旧单词变来的。一旦找到目标单词,就不再继续扩展。 当bfs找到了目标单词,就说明存在最短序列,然后利用深搜和回溯,依据反向图从目标单词反向查找,把经过的单词依次添加到路径中,当回到起始单词时,就找到了一条完整的转换序列。

代码

cpp 复制代码
class Solution {
public:
    unordered_set<string> dict, curLevel, nextLevel;
    unordered_map<string, vector<string>> graph;//反向图,存储每个单词的前一个可能的单词
    deque<string> path;//用于记录当前的转换路径
    vector<vector<string>> ans;//存储所有从beginWord到endWord的最短转换序列。
    //初始化函数,将wordList存储到dict中
    void build(vector<string>& wordList)
    {
        dict = unordered_set<string>(wordList.begin(), wordList.end());
        graph.clear();
        ans.clear();
        curLevel.clear();
        nextLevel.clear();
    }
    //找到所有从beginWord到endWord的最短转换序列
    vector<vector<string>> findLadders(string beginWord, string endWord, vector<string>& wordList) {
        build(wordList);//初始化
        if (dict.find(endWord) == dict.end())
        {
            return ans;
        }
        if (bfs(beginWord, endWord))//先调用bfs广搜,找到endword就深搜,找生成路径
        {
            dfs(endWord, beginWord);
        }
        return ans;
    }
    bool bfs(string begin, string end)//广搜从beginWord开始逐层扩展,构建反向图
    {
        bool find = false;
        curLevel.insert(begin);
        while (!curLevel.empty())
        {
            //移除当前层的单词
            for (const string& word : curLevel)
            {
                dict.erase(word);//避免重复使用
            }
            for (const string& word : curLevel)
            {
                string w = word;
                for (int i = 0; i < w.size(); i++)
                {
                    char old = w[i];
                    //每个位置的字符依次替换成a到z,检查替换后的单词是否在dict且不等于原单词
                    for (char ch = 'a'; ch <= 'z'; ch++)
                    {
                        w[i] = ch;
                        if (dict.find(w) != dict.end() && w != word)
                        {
                            if (w == end) {
                                find = true;
                            }
                            graph[w].push_back(word);
                            nextLevel.insert(w);
                        }
                    }
                    w[i] = old;
                }
            }
            if(find)
            {
                return true;
            }
            else//没找到endword
            {
                swap(curLevel, nextLevel);//交换curLevel和nextLevel,继续下一层的扩展
                nextLevel.clear();
            }
        }
        return false;
    }
    //回溯生成路径
    void dfs(string word, string aim) {
        path.push_front(word);
        if(word==aim)
        {
            ans.push_back(vector<string>(path.begin(), path.end()));
        }
        else if (graph.find(word)!=graph.end())
        {
            for(const string& next:graph[word])
            {
                dfs(next,aim);
            }
        }
        path.pop_front();
    }
};
相关推荐
2301_803554523 小时前
c++中类的前置声明
java·开发语言·c++
hn小菜鸡5 小时前
LeetCode 377.组合总和IV
数据结构·算法·leetcode
Deepoch6 小时前
Deepoc 大模型:无人机行业的智能变革引擎
人工智能·科技·算法·ai·动态规划·无人机
heimeiyingwang9 天前
【深度学习加速探秘】Winograd 卷积算法:让计算效率 “飞” 起来
人工智能·深度学习·算法
LyaJpunov9 天前
深入理解 C++ volatile 与 atomic:五大用法解析 + 六大高频考点
c++·面试·volatile·atomic
小灰灰搞电子9 天前
Qt PyQt与PySide技术-C++库的Python绑定
c++·qt·pyqt
时空自由民.9 天前
C++ 不同线程之间传值
开发语言·c++·算法
ai小鬼头9 天前
AIStarter开发者熊哥分享|低成本部署AI项目的实战经验
后端·算法·架构
小白菜3336669 天前
DAY 37 早停策略和模型权重的保存
人工智能·深度学习·算法
zeroporn9 天前
以玄幻小说方式打开深度学习词嵌入算法!! 使用Skip-gram来完成 Word2Vec 词嵌入(Embedding)
人工智能·深度学习·算法·自然语言处理·embedding·word2vec·skip-gram