写一些自己LeetCode的刷题过程及总结07(BFS)


##leetcode上有2000+的题,不可能都刷完,我的刷题顺序是先分类型,然后再分难度,不断提升,当然过程中也参考了其他大神们的一些建议,光刷题收获不大,最重要的还是不断归纳总结,没事刷两道,坚持写总结其实也挺有意思的。##
##还在不断更新总结!##
##本文仅用来记录自己平时的学习收获##
##有朝一日我也能写出漂亮的代码!##

一、深度优先搜索(BFS)

深度优先搜索通常借助队列的先进先出的特性来实现,对于树形结构来说就是,先遍历完一层再遍历下一层;对于图形结构来说就是,先遍历一圈再遍历下一圈。对于树和图的遍历来说既可以用DFS也可以用BFS,个人感觉借助队列的BFS更好理解一些,而且也更容易来实现,因为它有固定的模板,只要根据题意完成细节部分的实现就好。所以这里就先对BFS的题目进行总结。在之前的博客栈与队列中我已经列出了部分BFS的题目,这里只是更详细一些。

1.1 leetcode部分栈与队列题目及代码

752.打开转盘锁
994.腐烂的橘子
815.公交路线
690.员工的重要性
130.被围绕的区域
133.克隆图
200.岛屿数量
207.课程表
210.课程表II
310.最小高度树
417.太平洋大西洋水流问题
542.01矩阵

1、752.打开转盘锁

//用队列进行BFS
class Solution {
public:
    int openLock(vector<string>& deadends, string target) {
        unordered_set<string> set(deadends.begin(), deadends.end());
        if (set.count("0000") == 1) return -1;
        queue<string> que;
        que.push("0000");
        int count = 0;
        while (!que.empty()) {
            int len = que.size();
            for (int i = 0; i < len; ++i) {
                string str = que.front();
                que.pop();
                if (str == target) return count;
                // 处理str周围的八个相邻结点
                for (int j = 0; j < 4; ++j) {
                    //+1 、 -1
                    for (int k = -1; k < 2; k += 2) {
                        string cur = str;
                        cur[j] = (str[j] - '0' + 10 + k) % 10 + '0';
                        if (set.count(cur) != 1) {
                            set.insert(cur);
                            que.push(cur);
                        }
                    }
                }
            }
            // 本层队列中元素处理完成,到达下一转动步数,步数加1
            ++count;
        }
        return -1;
    }
};

2、994.腐烂的橘子

class Solution {
public:
    int orangesRotting(vector<vector<int>>& grid) {
        queue<pair<int, int>> que;
        int freshNum = 0;
        for (int i = 0; i < grid.size(); ++i) {
            for (int j = 0; j < grid[0].size(); ++j) {
                if (grid[i][j] == 1) ++freshNum;
                else if (grid[i][j] == 2) que.push({i, j});
            }
        }
        int minCount = 0;
        vector<pair<int, int>> dict = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
        while (!que.empty()) {
            int len = que.size();
            bool flag = false;
            for (int i = 0; i < len; ++i) {
                auto temp = que.front();
                que.pop();
                for (int j = 0; j < 4; ++j) {
                    int x = temp.first + dict[j].first;
                    int y = temp.second + dict[j].second;
                    if (x >=0 && x < grid.size() && y >= 0 && y < grid[0].size() && grid[x][y] == 1) {
                        grid[x][y] = 2;
                        --freshNum;
                        flag = true;
                        que.push({x, y});
                    }
                }
            }
            if (flag) ++minCount;
        }
        if (freshNum != 0) return -1;
        else return minCount;
    }
};

3、815.公交路线

class Solution {
public:
    int numBusesToDestination(vector<vector<int>>& routes, int source, int target) {
        if (source == target) return 0;
        // 标记站点出现的线路
        unordered_map<int, vector<int>> mp;
        // 标记访问的线路
        vector<bool> visited(routes.size(), false);
        // 记录站点出现的线路
        for (int i = 0; i < routes.size(); ++i) {
            for (int j = 0; j < routes[i].size(); ++j) {
                mp[routes[i][j]].push_back(i);
            }
        }
        queue<int> que;
        que.push(source);
        int step = 0;
        while (!que.empty()) {
            ++step;
            int len = que.size();
            for (int i = 0; i < len; ++i) {
                int temp = que.front();
                que.pop();
                for (int m : mp[temp]) {
                    if (!visited[m]) {
                        for (int n = 0; n < routes[m].size(); ++n) {
                            if (routes[m][n] == target) return step;
                            que.push(routes[m][n]);
                        }
                        visited[m] = true;
                    }
                }
            }
        }
        return -1;
    }
};

4、690.员工的重要性

class Solution {
public:
    int getImportance(vector<Employee *> employees, int id) {
        unordered_map<int, Employee *> mp;
        for (auto &employee : employees) {
            mp[employee->id] = employee;
        }

        int total = 0;
        queue<int> que;
        que.push(id);
        while (!que.empty()) {
            int curId = que.front();
            que.pop();
            Employee *employee = mp[curId];
            total += employee->importance;
            for (int subId : employee->subordinates) {
                que.push(subId);
            }
        }
        return total;
    }
};

5、130.被围绕的区域

class Solution {
public:
    void solve(vector<vector<char>>& board) {
        int dir[4][2] = {-1, 0, 1, 0, 0, -1, 0, 1};
        queue<pair<int, int>> que;
        int m = board.size();
        int n = board[0].size();
        for (int i = 0; i < m; ++i) {
            if (board[i][0] == 'O') {
                que.push({i, 0});
            }
            if (board[i][n - 1] == 'O') {
                que.push({i, n - 1});
            }
        }
        for (int j = 0; j < n; ++j) {
            if (board[0][j] == 'O') {
                que.push({0, j});
            }
            if (board[m - 1][j] == 'O') {
                que.push({m - 1, j});
            }
        }
        while (!que.empty()) {
            int x = que.front().first;
            int y = que.front().second;
            que.pop();
            board[x][y] = 'A';
            for (int k = 0; k < 4; ++k) {
                int dx = x + dir[k][0];
                int dy = y + dir[k][1];
                if (dx < 0 || dx >= m || dy < 0 || dy >= n || board[dx][dy] != 'O') {
                    continue;
                } else {
                    que.push({dx, dy});
                }
            }
        }
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                if (board[i][j] == 'A') {
                    board[i][j] = 'O';
                } else if (board[i][j] == 'O') {
                    board[i][j] = 'X';
                }
            }
        }
    }
};

6、133.克隆图

/*
// Definition for a Node.
class Node {
public:
    int val;
    vector<Node*> neighbors;
    Node() {
        val = 0;
        neighbors = vector<Node*>();
    }
    Node(int _val) {
        val = _val;
        neighbors = vector<Node*>();
    }
    Node(int _val, vector<Node*> _neighbors) {
        val = _val;
        neighbors = _neighbors;
    }
};
*/
class Solution {
public:
    Node* cloneGraph(Node* node) {
        if (node == nullptr) return node;
        unordered_map<Node*, Node*> visited;
        queue<Node*> q;
        // 将题目给定的节点添加到队列
        q.push(node);
        // 克隆第一个节点并存储到哈希表中
        visited[node] = new Node(node->val);
        while (!q.empty()) {
            // 取出队列的头节点
            auto cur = q.front();
            q.pop();
            // 遍历该节点的邻居
            for (auto neighbor : cur->neighbors) {
                if (visited.find(neighbor) == visited.end()) {
                    // 如果没有被访问过,就克隆并存储在哈希表中
                    visited[neighbor] = new Node(neighbor->val);
                    // 将邻居节点加入队列中
                    q.push(neighbor);
                }
                // 更新当前节点的邻居列表
                visited[cur]->neighbors.push_back(visited[neighbor]);
            }
        }
        return visited[node];
    }
};

7、200.岛屿数量

class Solution {
public:
    int numIslands(vector<vector<char>>& grid) {
        if (grid.size() == 0) return 0;
        int dir[4][2] = {-1, 0, 1, 0, 0, -1, 0, 1};
        int ret = 0;
        int m = grid.size();
        int n = grid[0].size();
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                if (grid[i][j] == '1') {
                    ++ret;
                    queue<pair<int, int>> q;
                    q.push({i, j});
                    while (!q.empty()) {
                        int x = q.front().first;
                        int y = q.front().second;
                        q.pop();
                        for (int k = 0; k < 4; ++k) {
                            int dx = x + dir[k][0];
                            int dy = y + dir[k][1];
                            if (dx >= 0 && dx < m && dy >= 0 && dy < n && grid[dx][dy] == '1') {
                                q.push({dx, dy});
                                grid[dx][dy] = '0';
                            }
                        }
                    }
                }                
            }
        }
        return ret;
    }
};

8、207.课程表

class Solution {
public:
    bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
        //记录所有顶点的入度,未初始化的为0
        vector<int> degrees(numCourses);
        //邻接表
        vector<vector<int>> adjacents(numCourses);
        for (int i = 0; i < prerequisites.size(); ++i) {
            //入顶点
            ++degrees[prerequisites[i][0]];
            //出顶点
            adjacents[prerequisites[i][1]].push_back(prerequisites[i][0]);
        }
        //零入度的顶点
        queue<int> q;
        int num = numCourses;
        for (int i = 0; i < numCourses; ++i) {
            if (degrees[i] == 0) {
                //入度为0的先入队列
                q.push(i);
                --num;
            }
        }
        while (!q.empty()) {
            int temp = q.front();
            q.pop();
            for (int i = 0; i < adjacents[temp].size(); ++i) {
                if (--degrees[adjacents[temp][i]] == 0) {
                    q.push(adjacents[temp][i]);
                    --num;
                }
            }
        }
        if (num == 0) return true;
        else return false;
    }
};

9、210.课程表II

//在上一道题的基础上略做修改即可
class Solution {
public:
    vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {
        vector<int> degrees(numCourses);
        vector<vector<int>> adjacents(numCourses);
        for (int i = 0; i < prerequisites.size(); ++i) {
            ++degrees[prerequisites[i][0]];
            adjacents[prerequisites[i][1]].push_back(prerequisites[i][0]);
        }
        vector<int> ret;
        queue<int> q;
        for (int i = 0; i < numCourses; ++i) {
            if (degrees[i] == 0) {
                q.push(i);
            }
        }
        while (!q.empty()) {
            int temp = q.front();
            q.pop();
            ret.push_back(temp);
            for (int i = 0; i < adjacents[temp].size(); ++i) {
                if (--degrees[adjacents[temp][i]] == 0) {
                    q.push(adjacents[temp][i]);
                }
            }
        }
        if (ret.size() != numCourses) return {};
        else return ret;
    }
};

10、310.最小高度树

class Solution {
public:
    vector<int> findMinHeightTrees(int n, vector<vector<int>>& edges) {
        // case case(边界条件)
        if (n == 1) return { 0 };
        // step1: 构建带度的无向图。 度定义为与当前顶点相邻的顶点(边)的数量!
        vector<vector<int>> g(n);
        vector<int> degrees(n); 
        for (const auto& e : edges) {
            ++degrees[e[0]];
            ++degrees[e[1]];
            g[e[0]].push_back(e[1]);
            g[e[1]].push_back(e[0]);
        }
        // 把所有度为1的节点,即叶节点加入队列
        queue<int> q;
        for (int i = 0; i < n; ++i) {
            if (degrees[i] == 1) {
                q.push(i);
            }
        }
        vector<int> ret;
        while (!q.empty()) {
            ret.clear();//这一步是核心
            int len = q.size();
            for (int i = 0; i < len; ++i) {
                int cur = q.front();
                q.pop();
                ret.push_back(cur);
                for (auto& c : g[cur]) {
                    if (--degrees[c] == 1) {
                        q.push(c);
                    }
                }
            }
        }
        return ret;
    }
};

11、417.太平洋大西洋水流问题

class Solution {
private:
    vector<vector<int>> ret;
    int dir[4][2] = {0, 1, 0, -1, 1, 0, -1, 0};
public:
    void bfs(vector<vector<int>>& heights, vector<vector<int>>& visited, int x, int y, int constrain, int inc) {
        //x 和 y 表示初始进行BFS的起点,constrain表示用于判断节点是否访问过,inc 表示访问节点时的自增程度
        queue<pair<int, int>> q;
        q.push({x, y});
        int m = heights.size();
        int n = heights[0].size();
        while (!q.empty()) {
            int len = q.size();
            for (int i = 0; i < len; ++i) {
                auto temp = q.front();
                q.pop();
                for (int j = 0; j < 4; ++j) {
                    int dx = temp.first + dir[j][0];
                    int dy = temp.second + dir[j][1];
                    if (dx < 0 || dx >= m || dy < 0 || dy >= n || visited[dx][dy] > constrain || heights[temp.first][temp.second] > heights[dx][dy]) {
                        continue;
                    }
                    q.push({dx, dy});
                    visited[dx][dy] += inc;
                }
            }
        }
    }

    vector<vector<int>> pacificAtlantic(vector<vector<int>>& heights) {
        int m = heights.size();
        int n = heights[0].size();
        vector<vector<int>> visited(m, vector<int> (n, 0));
        //两个太平洋边界
        for (int i = 0; i < n; ++i) {
            if (visited[0][i] == 0) {
                ++visited[0][i];
                bfs(heights, visited, 0, i, 0, 1);
            }
        }
        for (int i = 0; i < m; ++i) {
            if (visited[i][0] == 0) {
                ++visited[i][0];
                bfs(heights, visited, i, 0, 0, 1);
            }
        }
        //两个大西洋边界
        for (int i = 0; i < n; ++i) {
            if (visited[m - 1][i] <= 1) {
                visited[m - 1][i] += 2;
                bfs(heights, visited, m - 1, i, 1, 2);
            }
        }
        for (int i = 0; i < m; ++i) {
            if (visited[i][n - 1] <= 1) {
                visited[i][n - 1] += 2;
                bfs(heights, visited, i, n - 1, 1, 2);
            }
        }
        //找到交界处
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                if (visited[i][j] == 3) {
                    ret.push_back({i, j});
                }
            }
        }
        return ret;
    }
};

12、542.01矩阵

class Solution {
private:
    int dir[4][2] = {-1, 0, 1, 0, 0, -1, 0, 1};
public:
    vector<vector<int>> updateMatrix(vector<vector<int>>& mat) {
        int m = mat.size();
        int n = mat[0].size();
        vector<vector<int>> ret(m, vector<int> (n, 0));
        vector<vector<int>> vis(m, vector<int> (n, 0));
        queue<pair<int, int>> q;
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                if (mat[i][j] == 0) {
                    q.push({i, j});
                    vis[i][j] = 1;
                }
            }
        }
        while (!q.empty()) {
            auto pos = q.front();
            q.pop();
            int x = pos.first;
            int y = pos.second;
            for (int i = 0; i < 4; ++i) {
                int dx = x + dir[i][0];
                int dy = y + dir[i][1];
                if (dx >= 0 && dx < m && dy >= 0 && dy < n && vis[dx][dy] != 1) {
                    ret[dx][dy] = ret[x][y] + 1;
                    q.push({dx, dy});
                    vis[dx][dy] = 1;
                }
            }
        }
        return ret;
    }
};

1.2 总结

做了这些题目后也不难发现,BFS的解法其实是有一个模板的,只要在这个基础上根据题意对细节部分进行实现就好。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值