Word Ladder Ⅱ -- 广度优先搜索--力扣101算法题解笔记

6.4Word Ladder Ⅱ -- 广度优先搜索

这个题太难搞了!先说明一下

题目描述

给定一个起始字符串和一个终止字符串,以及一个单词表,求是否可以将其实字符串每次改一个字符,直到改成终止字符串,且所有中间的修改过程表示的字符串都可以在单词表里找到。若存在,输出需要修改次数最少的所有更改方式

输入输出样例

Input: beginWord = "hit", endWord = "cog",

wordList = "hot","dot","dog","lot","log","cog"

Output:

\["hit","hot","dot","dog","cog"\], \["hit","hot","lot","log","cog"

]

输入两个字符串,输出一个二维字符串数组,表示每种字符串修改方式。

题解

我们可以把起始字符串,终止字符串,以及单词表里的所有字符串想象成节点。若两个字符串只有一个字符不同,那么它们相连。因为题目需要输出修改次数最少的所有修改方式,因此我们可以使用广度优先搜索,求得起始节点到终止节点的最短距离。

还需要用到一个小技巧:我们把"从起始节点进行广度优先搜索,直到找到终止节点",转变为"从起始节点和终止节点分别进行广度优先搜索,每次只延展当前层节点数最少的那一端",通过这种方法,减少搜索的总结点数。

搜索结束后,还得用回溯法来重建所有可能的路径

cpp 复制代码
#include <vector>
#include <iostream>
#include <unordered_set>
#include <unordered_map>
using namespace std;

// 辅函数
void backtracking(const string& src, const string& dst, unordered_map<string, vector<string>>& next, vector<string>& path, vector<vector<string>>& ans) {
    if (src == dst) {
        ans.push_back(path);
        return;
    }
    for (const auto& s : next[src]) {
        path.push_back(s);
        backtracking(s, dst, next, path, ans);
        path.pop_back();
    }
}

// 主函数
vector<vector<string>> findLadders(string beginWord, string endWord, vector<string>& wordList) {
    vector<vector<string>> ans;
    unordered_set<string> dict;
    for (const auto& w : wordList) {
        dict.insert(w);
    }

    if (!dict.count(endWord)) {
        return ans;
    }

    dict.erase(beginWord);
    dict.erase(endWord);
    unordered_set<string> q1{ beginWord }, q2{ endWord };
    unordered_map<string, vector<string>> next;
    bool reversed = false, found = false;
    while (!q1.empty()) {
        unordered_set<string> q;
        for (const auto& w : q1) {
            string s = w;
            for (size_t i = 0; i < s.size(); i++) {
                char ch = s[i];
                for (int j = 0; j < 26; j++) {
                    s[i] = j + 'a';
                    if (q2.count(s)) {
                        reversed ? next[s].push_back(w) : next[w].push_back(s);
                        found = true;
                    }
                    if (dict.count(s)) {
                        reversed ? next[s].push_back(w) : next[w].push_back(s);
                        q.insert(s);
                    }
                }
                s[i] = ch;
            }
        }
        if (found) {
            break;
        }
        for (const auto& w : q) {
            dict.erase(w);
        }

        if (q.size() <= q2.size()) {
            q1 = q;
        }
        else {
            reversed = !reversed;
            q1 = q2;
            q2 = q;
        }
    }
    if (found) {
        vector<string> path = { beginWord };
        backtracking(beginWord, endWord, next, path, ans);
    }
    return ans;
}

int main() {
    string beginWord = "hit", endWord = "cog";
    vector<string> wordList = { "hot","dot","dog","lot","log","cog" };
    vector<vector<string>> res = findLadders(beginWord, endWord, wordList);
    cout << "Output:" << endl;
    cout << "[" << endl;
    for (int i = 0; i < res.size(); ++i) {
        cout << "  [";
        for (int j = 0; j < res[i].size(); ++j) {
            cout << "\"" << res[i][j] << "\"";
            if (j != res[i].size() - 1) cout << ",";
        }
        cout << "]";
        if (i != res.size() - 1) cout << ",";
        cout << endl;
    }
    cout << "]" << endl;
    return 0;
}
相关推荐
isyangli_blog1 小时前
OpenDayLight (Carbon 版本) 启动与组件安装
开发语言·php
vb2008111 小时前
FastAPI APIRouter
开发语言·python
Benszen1 小时前
KVM虚拟化解决方案
开发语言·perl
会编程的土豆1 小时前
Go 语言反射(Reflection)详解
开发语言·后端·golang
東雪木1 小时前
多线程与并发编程 专属复习笔记
java·开发语言·笔记·java面试
杨充2 小时前
1.3 浮点型数据设计灵魂
开发语言·python·算法
噜噜噜阿鲁~2 小时前
python学习笔记 | 11.3、面向对象高级编程-多重继承
java·开发语言
basketball6162 小时前
Go 语言从入门到进阶:4. 数组和MAP使用方法总结
开发语言·后端·golang
春生野草2 小时前
反射、Tomcat执行
java·开发语言
雪的季节3 小时前
企业级 Qt 全功能项目
开发语言·数据库·qt