leetcode:126. 单词接龙 II(没有做出来)

题目来源

题目描述

在这里插入图片描述

题目解析

两个单词只有一个字母之差,它们就是邻接关系,我们可以从wordList中得到一张邻接表
在这里插入图片描述
将这张表转换成无向图。邻接节点用一条无向边相连:
在这里插入图片描述
题目等价为:在图中找到起点到终点词的最短路径。题目中,起始词没有出现在单词表中,加进入就行。

路径最短意味着什么?hit -> hot -> lot -> log,这是一条转变路径,hit在第0层,hot在第1层……从起始词到终点词经历的层数,是路径的长度。最短路径代表终点词在路径中的层尽量小。
在这里插入图片描述
求“最短路径”、“最小深度”——BFS

  • 每个单词节点有自己的层,它的“邻居”是它可变成的单词,属于下一层。
  • 这很像 BFS:考察当前层出列的节点,带出下一层的节点入列。

怎么找到自己的 “邻居单词”

  • 让单词的每个字母逐个改动,生成25个新单词。选出存在于wordList的,就是“邻居单词”。

路径上出现过的单词,就不要让它再出现

  • 比如:hit->hot->hit ,又变回来,即重复访问节点,徒增路径长度。用一个 visited 容器,记录遍历过的单词节点。

为什么还需要 DFS?

  • 如果是求最短路径的长度,仅 BFS 即可。但要找出最短路径的所有组合,则需要回溯。
  • 我们可以从起点词开始DFS,也可以从终点词开始 DFS,我选择后者,遇到起点词,就找到一条满足条件的路径,推入结果数组,然后回溯,直到找出所有最短路径。

在这里插入图片描述

不能边计算长度边计算路径吗?不能,原因如下:
在这里插入图片描述

class Solution {
public:
    vector<vector<string>> findLadders(string beginWord, string endWord, vector<string>& wordList) {
        unordered_set<string> search(wordList.begin(), wordList.end()); // hash 提高转换(查找)效率
        vector<vector<string>> res;
        deque<vector<string>> worker; // 层节点容器
        worker.push_back({beginWord}); // beginWord 作为起始的根节点
        while (!worker.empty()) {
            unordered_set<string> visited; // 一层内已转化过的 string 容器。set避免重复保存
            for (int i = worker.size(); i > 0; --i) { // 层遍历
                auto sub = worker.front(); worker.pop_front(); // 获取单个节点
                auto tail = sub.back(); // 获取单个节点内的最后一个 string 元素
                if (tail == endWord) { // 是在到达是转换的终点
                    res.push_back(sub);
                    continue;
                }
                for (int j = 0; j < tail.size(); ++j) { // 回溯试探 下层 节点的元素的可能性
                    char temp = tail[j]; // 单个 string 回溯保存状态
                    for (char c = 'a'; c <= 'z'; ++c) {
                        if (c == temp) continue; // 忽略原始状态
                        tail[j] = c;
                        if (!search.count(tail)) continue; // 未找到转换序
                        visited.insert(tail); // 找到转换序,保存 已使用 转换
                        sub.push_back(tail); // 节点 回溯
                        worker.push_back(sub); // 向容器内保存 子节点
                        sub.pop_back(); // 回溯恢复
                    }
                    tail[j] = temp; // string 回溯恢复状态
                }
            }
            if (res.size()) return res; // 第一次到达 树底,也就是得到最小转换序
            for (auto &w : visited) search.erase(w); // 删除已使用的转换序
        }
        return {};
    }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值