广度优先搜索 leetcode: 323 107 剑指 Offer 32

使用广度优先遍历得到无权图的最短路径

 

在 无权图 中,由于广度优先遍历本身的特点,假设源点为 source,只有在遍历到 所有 距离源点 source 的距离为 d 的所有结点以后,才能遍历到所有 距离源点 source 的距离为 d + 1 的所有结点。也可以使用「两点之间、线段最短」这条经验来辅助理解如下结论:从源点 source 到目标结点 target 走直线走过的路径一定是最短的。

图论中最短路径问题

在图中,由于 图中存在环,和深度优先遍历一样,广度优先遍历也需要在遍历的时候记录已经遍历过的结点。特别注意:将结点添加到队列以后,一定要马上标记为「已经访问」,否则相同结点会重复入队,这一点在初学的时候很容易忽略。如果很难理解这样做的必要性,建议大家在代码中打印出队列中的元素进行调试:在图中,如果入队的时候不马上标记为「已访问」,相同的结点会重复入队,这是不对的。

323. 无向图中连通分量的数目

中等

company

你有一个包含 n 个节点的图。给定一个整数 n 和一个数组 edges ,其中 edges[i] = [ai, bi] 表示图中 ai 和 bi 之间有一条边。

返回 图中已连接分量的数目 。

示例 1:

输入: n = 5, edges = [[0, 1], [1, 2], [3, 4]]
输出: 2

示例 2:

输入: n = 5, edges = [[0,1], [1,2], [2,3], [3,4]]
输出:  1

提示:

  • 1 <= n <= 2000
  • 1 <= edges.length <= 5000
  • edges[i].length == 2
  • 0 <= ai <= bi < n
  • ai != bi
  • edges 中不会出现重复的边

解题思路:

通过广度优先搜索算法遍历图中的所有顶点,并通过使用一个布尔型向量来标记已经访问过的顶点。每次从一个未访问的顶点开始进行广度优先搜索时,就会找到一个新的连通分量,计数器就会加1。最终返回计数器的值就是最终的结果。

class Solution {
public:
    int countComponents(int n, vector<vector<int>>& edges) {
        vector<vector<int>>adj;
        adj.resize(n);
        for(int i=0; i<edges.size(); i++){ // 建图
            adj[edges[i][0]].push_back(edges[i][1]);
            adj[edges[i][1]].push_back(edges[i][0]);
        }
        vector<bool>vis(n,false);
        int ans = 0; // 记次
        for(int i=0; i<adj.size(); i++){
            if(!vis[i]){
                bfs(adj,i,vis);
                ans++;
            }
        }  
        return ans;
    }

    void bfs(vector<vector<int>>&adj,int i,vector<bool>& vis){
        queue<int>que;
        que.push(i);
        vis[i] = true;
        while(!que.empty()){
            int temp = que.front();
            que.pop();
            for(int j=0; j<adj[temp].size(); j++){
                int v = adj[temp][j];
                if(!vis[v]){
                    que.push(v);
                    vis[v] = true;
                }
            }
        }
    }
};

107. 二叉树的层序遍历 II

中等

给你二叉树的根节点 root ,返回其节点值 自底向上的层序遍历 。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)

示例 1:

输入:root = [3,9,20,null,null,15,7]
输出:[[15,7],[9,20],[3]]

示例 2:

输入:root = [1]
输出:[[1]]

示例 3:

输入:root = []
输出:[]

提示:

  • 树中节点数目在范围 [0, 2000] 内
  • -1000 <= Node.val <= 1000

解题思路:

  1. 创建一个队列queue,用于存储待访问的节点。
  2. 如果根节点root不为空,将其入队。
  3. 创建一个二维向量result,用于存储层序遍历的结果。
  4. 进行广度优先搜索,并且将当前层的节点值向量level插入到result向量的开头,即逆序插入。
/**  
 * Definition for a binary tree node.  
 * struct TreeNode {  
 *     int val;  
 *     TreeNode *left;  
 *     TreeNode *right;  
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}  
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}  
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}  
 * };  
 */  
class Solution {  
public:  
    vector<vector<int>> levelOrderBottom(TreeNode* root) {  
        queue<TreeNode*> queue;  
        if (root != nullptr) queue.push(root);  
        vector<vector<int>> result;  
        while (!queue.empty()) {  
            int n = queue.size();  
            vector<int> level;  
            for (int i = 0; i < n; i++) {  
                TreeNode* node = queue.front();  
                queue.pop();  
                if (node != nullptr) level.push_back(node->val);  
                if (node->left) queue.push(node->left);  
                if (node->right) queue.push(node->right);  
            }  
            result.insert(result.begin(), level);  
        }  
        return result;  
    }  
};

剑指 Offer 32 - III. 从上到下打印二叉树 III

中等

请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,其他行以此类推。

例如:
给定二叉树: [3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7

返回其层次遍历结果:

[
  [3],
  [20,9],
  [15,7]
]

提示:

  1. 节点总数 <= 1000

解题思路:

和上一题思路一致,不过这个题存的顺序会左右颠倒,可以借助reverse(temp.begin(),temp.end());使得存的顺序颠倒即可。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        queue<TreeNode*>que;
        if(root != nullptr) que.push(root);
        vector<vector<int>>res;
        int level = 1;
        while(!que.empty()){
            int n = que.size();
            vector<int>temp;
            level++;
            for(int i=0; i<n; i++){
                TreeNode* node = que.front();
                que.pop();
                if(node != nullptr) temp.push_back(node -> val);
                if(node -> left) que.push(node -> left);
                if(node -> right) que.push(node -> right);
            }
            if(level % 2 == 0)
            res.push_back(temp);
            else{
                reverse(temp.begin(),temp.end());
                res.push_back(temp);
            }
        }
        return res;
    }
};

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值