使用广度优先遍历得到无权图的最短路径
在 无权图 中,由于广度优先遍历本身的特点,假设源点为 source,只有在遍历到 所有 距离源点 source 的距离为 d 的所有结点以后,才能遍历到所有 距离源点 source 的距离为 d + 1 的所有结点。也可以使用「两点之间、线段最短」这条经验来辅助理解如下结论:从源点 source 到目标结点 target 走直线走过的路径一定是最短的。
图论中最短路径问题
在图中,由于 图中存在环,和深度优先遍历一样,广度优先遍历也需要在遍历的时候记录已经遍历过的结点。特别注意:将结点添加到队列以后,一定要马上标记为「已经访问」,否则相同结点会重复入队,这一点在初学的时候很容易忽略。如果很难理解这样做的必要性,建议大家在代码中打印出队列中的元素进行调试:在图中,如果入队的时候不马上标记为「已访问」,相同的结点会重复入队,这是不对的。
323. 无向图中连通分量的数目
中等
你有一个包含 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
解题思路:
- 创建一个队列
queue
,用于存储待访问的节点。- 如果根节点
root
不为空,将其入队。- 创建一个二维向量
result
,用于存储层序遍历的结果。- 进行广度优先搜索,并且将当前层的节点值向量
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] ]
提示:
节点总数 <= 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;
}
};