bfs 刷题模版「1」

140 阅读2分钟

这是我参与8月更文挑战的第16天,活动详情查看:8月更文挑战

既然说是模版,可以解决哪些类型的题目是关键:

  1. 层序遍历 → 输出各种样式的结果
  2. 树宽度 → 横向最长,也只有层序遍历之后才知道结果
  3. 最短路 → 无权最短路径问题

来几个题,就知道模版是啥了。

题目

先看 BFS 最常见操作:层序遍历

层序遍历

    3
   / \
  9  20
    /  \
   15   7

// output: 
[
  [3],
  [9,20],
  [15,7]
]

每一层是每一行的输出,说明几个点:

  1. 你要存储每一层的 node,不然怎么输出
  2. 从上至下层次输出

先定义结果:vector<vector<int>> res ,然后需要在扫描每一层的时候,把当前层的nodes加入到内层的 vector<int> l

vector<vector<int>> res;    // 总的输出

vector<int> l;       // 每一行存储
int n = q.size();    // 每次push进来的都是下一层的全部元素
// n 是当前层的全部数量,不管之后的push,这个就是当前这个时刻的数量
while(n--) {
    TreeNode* t = q.front();
    q.pop();
    l.push_back(t->val);
    // push queue
}
res.push_back(l);    // 每次循环完都会把当前层的结果,加入到总的结果中

输出完成了,来看看怎么把树遍历起来:

queue<TreeNode*> q;    // 全局 queue,父节点进入
if (root) q.push(root);

while(q.size()) {
    vector<int> l;
    int n = q.size();

    while(n--) {
        TreeNode* t = q.front();
        q.pop();
        // 加入 node 输出结果
	// 把当前的子节点加入到 queue
        if (t->left) q.push(t->left);
        if (t->right) q.push(t->right);
    }
    
}

Z型遍历

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

板子基本是这个,区别在于输出:正反正反 -> 在输出的时候判断奇偶即可:

  1. 声明返回的结果,队列
  2. 插入 root 到队列
  3. 循环判断队列不为空
  4. 弹出队列头部元素,将其左子树node,右子树node,push到队列中
  5. 把当前访问的元素插入当前层的结果中
  6. 当前层没有元素 (会记录当前的数量:n,也就是还没插入左右子树的那个瞬间)
  7. 判断奇偶,是否reverse一下 (所以这不是访问顺序,直接显示顺序,完全可以由reverse完成)
  8. 插入最终结果
vector<vector<int>> res;
queue<TreeNode*> q;
if (root) q.push(root);

int cnt = 0;
while (q.size()) {
    vector<int> l;
    int n = q.size();
    while (n--) {
        auto t = q.front();
        q.pop();
        if (t->left) q.push(t->left);
        if (t->right) q.push(t->right);
        l.push_back(t->val);
    }

    if (cnt % 2 == 1) reverse(l.begin(), l.end());
    cnt++;
    res.push_back(l);
}
return res;