Leetcode 102.二叉树的层次遍历

题目:102. 二叉树的层次遍历

与前序、中序、后序遍历相反,层次遍历的迭代实现是比较简单的。因为是从上到下,从左到右进行遍历,所以可以利用队列先进先出的性质保存中间结果。首先还是判空,如果root为空直接return空向量;否则将root入队列,并且作为第一层的遍历结果存入res中。遍历由两层循环实现,外循环用于将本层的遍历结果curLevel存入res,内循环通过访问上一层的遍历结果(即队列的前端),将其子节点保存作为本层遍历结果,同时被访问过的上层节点出队列。(这个过程自己动手画一下就很清楚了~)外循环的终止条件是队列为空,含义是上一层遍历中没有加入任何新的子节点,已经是最后一层(叶子节点)了。内层循环的终止条件是遍历次数达到上次遍历结束后队列的长度,即上层节点个数。

class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        if (root == NULL) return {};
        vector<vector<int>> res;
        queue<TreeNode*> q;
        q.push(root);
        TreeNode* curNode;
        int size;
        while (!q.empty()) {
            size = q.size();
            vector<int> curLevel;
            //每次都是从上一层的遍历结果中取出节点进行遍历
            for (int i = 0; i < size; i++) {
                curNode = q.front();
                q.pop();
                curLevel.push_back(curNode->val);
                if (curNode->left) q.push(curNode->left);
                if (curNode->right) q.push(curNode->right);
            }
            res.push_back(curLevel);
        }
        return res;
    }
};

为了清楚地表现出分析的过程,所以每一层都申请了一个临时变量curLevel,但是这个变量真的有必要存在吗?其实res就已经蕴含了这个变量,所以只需要一个int变量指明当前是哪一层就好了,修改代码如下:

// 优化后,执行用时有了显著提升
class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        if (root == NULL) return {};
        vector<vector<int>> res;
        queue<TreeNode*> q;
        q.push(root);
        TreeNode* curNode;
        int size;
        int curLevel = 0;
        while (!q.empty()) {
            size = q.size();
            res.push_back({});
            for (int i = 0; i < size; i++) {
                curNode = q.front();
                q.pop();
                res[curLevel].push_back(curNode->val);
                if (curNode->left) q.push(curNode->left);
                if (curNode->right) q.push(curNode->right);
            }
            curLevel++;
        }
        return res;
    }
};

接下来看看递归的写法。首先可以明确的是与前序、中序、后序遍历所用的DFS不同,层次遍历用到的是BFS,因此只需写一个BFS函数,在levelOrder中进行调用即可。首先对BFS函数进行接口设计,root指针是必不可少;res也需要在递归的过程中进行更新,所以作为出参传入;而对照上面的迭代版本,这里面有一个很明显的变量 – 层次,因此还需要一个参数:curLevel。因为是递归,所以显而易见的会有对左右子节点分别调用BFS函数这一步,在这之前需要把当前节点的值存入结果变量,那么什么时候将当前层的结果存入res中呢?因为res的每一个元素是一个代表了当前层遍历结果的一维向量,所以res的大小就是当前层数,当传入的curLevel等于res大小时,表明开始了新一层的遍历,需要将cur放入res中。if (res.size() == curLevel) res.push_back({}); 和 res[curLevel].push_back(root->val); 大概是整个递归版本里最难想到的两处,但其实如果一开始能把迭代想清楚,尤其是优化部分,其实转成递归就是顺其自然的事了~

// 在想到优化迭代版本之前写的递归,没有意识到res中已经包含了cur以及curLevel的作用,所以写出了错误的代码
class Solution {
public:
    // 递归
    void bfs(TreeNode* root, int curLevel, vector<vector<int>>& res) {
        if (!root) return;
        // 当前层次节点放入res中
        vector<int> cur;
        cur.push_back(root->val);
        if (res.size() == curLevel) res.push_back(cur);
        if (root->left) bfs(root->left, curLevel + 1, res);
        if (root->right) bfs(root->right, curLevel + 1, res);
    }
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>> res;
        int curLevel = 0;
        bfs(root, curLevel, res);
        return res;
    }
};

最终递归代码如下:

class Solution {
public:
    // 递归
    void bfs(TreeNode* root, int curLevel, vector<vector<int>>& res) {
        if (!root) return;
        // 当前层次节点放入res中
        if (res.size() == curLevel) res.push_back({});
        res[curLevel].push_back(root->val);
        if (root->left) bfs(root->left, curLevel + 1, res);
        if (root->right) bfs(root->right, curLevel + 1, res);
    }
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>> res;
        int curLevel = 0;
        bfs(root, curLevel, res);
        return res;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值