gh_mirrors/leet/leetcode项目:最短路径算法题解分析

gh_mirrors/leet/leetcode项目:最短路径算法题解分析

【免费下载链接】leetcode LeetCode题解,151道题完整版。广告:推荐刷题网站 https://www.lintcode.com/?utm_source=soulmachine 【免费下载链接】leetcode 项目地址: https://gitcode.com/gh_mirrors/leet/leetcode

你是否在面对最短路径问题时感到无从下手?是否想快速掌握高效的路径搜索方法?本文将通过gh_mirrors/leet/leetcode项目中的经典例题,带你一文掌握广度优先搜索(BFS)在最短路径问题中的应用,从基础原理到实战技巧,让你轻松应对各类路径查找挑战。

最短路径与BFS算法基础

在解决最短路径问题时,广度优先搜索(Breadth-First Search, BFS)是最常用的算法之一。BFS通过逐层扩展节点的方式,能够保证在找到目标节点时,所经过的路径一定是最短的。项目中C++/chapBFS.tex文件详细介绍了BFS的实现框架和核心思想。

BFS算法的核心在于使用队列(Queue)来存储待访问的节点,并通过"先进先出"的特性实现逐层搜索。算法主要包含三个关键步骤:

  • 状态表示:确定每个节点需要存储哪些必要信息
  • 状态扩展:如何从当前节点生成新的可达节点
  • 重复判断:如何避免节点被多次访问导致的无限循环

单词接龙问题实战分析

问题描述与分析

Word Ladder(单词接龙)问题要求从起始单词逐步转换到目标单词,每次只能改变一个字母,且中间单词必须存在于字典中。例如,将"hit"转换为"cog",字典为["hot","dot","dog","lot","log"],最短路径为"hit" -> "hot" -> "dot" -> "dog" -> "cog",长度为5。

这是一个典型的最短路径问题,适合使用BFS求解。项目中提供了多种实现方法,包括单队列、双队列等不同优化策略。

单队列实现方案

单队列实现是BFS最基础的形式,通过在状态结构体中记录当前单词和层级信息,实现路径长度的追踪:

struct state_t {
    string word;
    int level;
    
    state_t(const string& word, int level) {
        this->word = word;
        this->level = level;
    }
};

int ladderLength(const string& start, const string &end, const unordered_set<string> &dict) {
    queue<state_t> q;
    unordered_set<state_t> visited;  // 判重
    
    q.push(state_t(start, 0));
    visited.insert(state_t(start, 0));
    
    while (!q.empty()) {
        const auto state = q.front();
        q.pop();
        
        if (state.word == end) {
            return state.level + 1;
        }
        
        // 扩展节点...
    }
    return 0;
}

双队列优化策略

双队列实现通过使用两个队列(当前层和下一层)来优化内存使用,不需要在状态中存储层级信息:

int ladderLength(const string& start, const string &end, const unordered_set<string> &dict) {
    queue<string> current, next;    // 当前层,下一层
    unordered_set<string> visited;  // 判重
    int level = -1;  // 层次
    
    current.push(start);
    visited.insert(start);
    
    while (!current.empty()) {
        ++level;
        while (!current.empty()) {
            const auto state = current.front();
            current.pop();
            
            if (state == end) {
                return level + 1;
            }
            
            // 扩展节点...
        }
        swap(next, current);
    }
    return 0;
}

两种实现的完整代码可参考项目中的C++/chapBFS.tex文件。

多路径查找与图的BFS

Word Ladder II问题解析

Word Ladder II问题是Word Ladder的扩展,要求找出所有可能的最短转换序列。这需要记录每个节点的多个前驱,形成有向无环图(DAG),再通过回溯法生成所有路径。

图的BFS实现

另一种思路是将问题抽象为图的最短路径查找。首先基于字典构建单词转换图,然后通过BFS查找所有最短路径:

vector<vector<string> > findLadders(const string& start, const string &end, const unordered_set<string> &dict) {
    const auto& g = build_graph(dict);  // 构建图
    queue<state_t*> q; 
    unordered_map<string, int> visited;
    
    q.push(create_state(nullptr, start, 0, pool));
    
    while (!q.empty()) {
        state_t* state = q.front();
        q.pop();
        
        if (state->word == end) {
            // 生成路径...
        }
        
        // 扩展节点...
    }
    return result;
}

构建图的关键代码如下:

unordered_map<string, unordered_set<string> > build_graph(const unordered_set<string>& dict) {
    unordered_map<string, unordered_set<string> > adjacency_list;
    
    for (const auto& word : dict) {
        for (size_t i = 0; i < word.size(); ++i) {
            string new_word(word);
            for (char c = 'a'; c <= 'z'; c++) {
                if (c == new_word[i]) continue;
                
                swap(c, new_word[i]);
                
                if ((dict.find(new_word) != dict.end())) {
                    adjacency_list[word].insert(new_word);
                }
                swap(c, new_word[i]); // 恢复该单词
            }
        }
    }
    return adjacency_list;
}

完整实现可参考C++/chapBFS.tex中的"图的广搜"部分。

二维网格中的最短路径

Surrounded Regions问题

Surrounded Regions问题要求找出所有被'X'包围的'O'区域,并将其转换为'X'。这可以通过从边界上的'O'开始BFS,标记所有可达的'O',最后未被标记的'O'即为被包围的区域。

被包围区域示意图

BFS实现策略

void solve(vector<vector<char>> &board) {
    if (board.empty()) return;
    
    const int m = board.size();
    const int n = board[0].size();
    
    // 从边界开始BFS
    for (int i = 0; i < n; i++) {
        bfs(board, 0, i);
        bfs(board, m - 1, i);
    }
    for (int j = 1; j < m - 1; j++) {
        bfs(board, j, 0);
        bfs(board, j, n - 1);
    }
    
    // 标记转换
    for (int i = 0; i < m; i++)
        for (int j = 0; j < n; j++)
            if (board[i][j] == 'O')
                board[i][j] = 'X';
            else if (board[i][j] == '+')
                board[i][j] = 'O';
}

BFS函数实现:

void bfs(vector<vector<char>> &board, int i, int j) {
    typedef pair<int, int> state_t;
    queue<state_t> q;
    const int m = board.size();
    const int n = board[0].size();
    
    state_t start = { i, j };
    if (state_is_valid(start)) {
        board[i][j] = '+';  // 标记为已访问
        q.push(start);
    }
    
    while (!q.empty()) {
        auto cur = q.front();
        q.pop();
        auto new_states = state_extend(cur);
        for (auto s : new_states) q.push(s);
    }
}

完整代码可参考C++/chapBFS.tex中的"Surrounded Regions"部分。

BFS算法小结与模板

BFS适用场景

BFS算法适用于以下场景:

  • 输入数据为树或图结构
  • 状态转换图为树或DAG图
  • 求解目标为最短路径或最少步骤

BFS思考步骤

  1. 确定是求路径长度还是路径本身
  2. 设计状态表示方法
  3. 实现状态扩展逻辑
  4. 设计重复判断机制
  5. 确定目标状态检测方式

BFS代码模板

状态表示
/** 状态 */
struct state_t {
    int data1;  /** 状态的数据,可以有多个字段 */
    int data2;
    int level;  /** 所在的层次 */
    
    bool operator==(const state_t &other) const {
        return /* 根据具体问题实现 */;
    }
};

// 定义hash函数
namespace std {
    template<> struct hash<state_t> {
        size_t operator()(const state_t & x) const {
            return /* 根据具体问题实现 */;
        }
    };
}
BFS主框架
// 求最短路径长度
int bfs(const State& start, const State& target) {
    queue<State> q;
    unordered_set<State> visited;
    
    q.push(start);
    visited.insert(start);
    
    while (!q.empty()) {
        State current = q.front();
        q.pop();
        
        if (current == target) {
            return current.level;
        }
        
        vector<State> nextStates = extend(current);
        for (const auto& next : nextStates) {
            if (visited.find(next) == visited.end()) {
                visited.insert(next);
                q.push(next);
            }
        }
    }
    
    return -1; // 没找到路径
}

完整模板可参考C++/chapBFS.tex中的"小结"部分。

总结与扩展

通过gh_mirrors/leet/leetcode项目中的BFS算法实现,我们学习了如何利用广度优先搜索解决各类最短路径问题。从单词接龙到网格区域查找,BFS算法展现了其在最短路径问题中的强大能力。

项目中还提供了更多BFS相关的题目和实现,如双向BFS、A*搜索等优化算法,感兴趣的读者可以进一步研究C++/chapBFS.tex文件,深入探索BFS的更多应用场景和优化策略。

掌握BFS算法不仅能帮助你解决算法题目,还能在实际开发中应对路径规划、网络爬虫、层次遍历等实际问题。希望本文能为你理解和应用BFS算法提供帮助。

要获取完整的题解代码和更多算法解析,可以通过以下方式获取项目:

git clone https://gitcode.com/gh_mirrors/leet/leetcode

通过实际运行和修改代码,你将更深入地理解BFS算法的精髓和应用技巧。

【免费下载链接】leetcode LeetCode题解,151道题完整版。广告:推荐刷题网站 https://www.lintcode.com/?utm_source=soulmachine 【免费下载链接】leetcode 项目地址: https://gitcode.com/gh_mirrors/leet/leetcode

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值