【面试题32-lll】 从上到下打印二叉树 III

题目描述:(来源于力扣 剑指offer32)

Alt


这道题和前面的两题比较类似,
1)层序遍历
2)分行从上到下打印二叉树
这道题,
3)之字形打印二叉树
需要考虑3点:

  • 层序遍历二叉树
  • 分层打印
  • 之字形(奇数层和偶数层顺序不同)

层序遍历二叉树可以考虑使用队列存储节点的值;
分层打印可以考虑计算队列中元素的个数来换行;
之字形打印,奇数层正序,偶数层逆序,通过层数的奇偶性来判断。

下面使用两种方式来实现:层序遍历+双栈 or 层序遍历+队列+deque

1)层序遍历+双栈

如果只是层序遍历二叉树,那么使用队列就可以满足要求。但是这里有正序、逆序的要求,所以队列不如栈比较方便。
使用两个栈,思路很简单,将其分为奇数层栈偶数层栈
Alt只需要判断层的奇偶性,将子节点数据压入对应的栈,即可。需要注意的是由于正序和逆序的区别,不同栈左右子节点压入的顺序不同。
具体实现:

class Solution {
private:
    int level=1;

    vector<int> stackLevel(stack<TreeNode*> &s, stack<TreeNode*> &sS, bool flag){
        //第一个参数是主栈,当前节点
        //第二个参数是存储子节点
        //flag:奇偶性,因为需要根据奇偶性判断子节点的压入顺序
        vector<int> res1;
        int sSize=s.size();//主栈的元素个数,用于分层打印
        for(int i=0; i<sSize; ++i){
            TreeNode* cur=s.top();
            res1.push_back(cur->val);
            s.pop();

            if(flag){//子节点压入
                if(cur->left!=nullptr)
                    sS.push(cur->left);
                if(cur->right!= nullptr)
                    sS.push(cur->right);
            }else{
                if(cur->right!= nullptr)
                    sS.push(cur->right);
                if(cur->left!=nullptr)
                    sS.push(cur->left);
            }
        }
        level++;//层数控制
        return res1;
    }

public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>> res2;
        
        if(root==nullptr)
            return res2;

        stack<TreeNode*> s1;    //奇层
        stack<TreeNode*> s2;    //偶层
        s1.push(root);
        while (!s1.empty() || !s2.empty()){ //只有当两个栈都为空时,才表示结束

            if(level % 2 != 0) //层数的奇偶性判断
                res2.push_back(stackLevel(s1,s2,true)); 
            else
                res2.push_back(stackLevel(s2,s1,false));
        }
        return res2;
    }
};
2)层序遍历+队列+deque

使用双栈存储,实现之字形打印的思路比较简洁,分开存储奇偶即可。
那如果不分开存储,应该使用哪种数据结构来存储,才能实现奇偶的不同遍历?

答案是deque
deque是一个可以双端插入和删除的队列,我们可以使用这个特性:
1)奇数层——正序打印,在deque的尾端依次插入;
2)偶数层——逆序打印,在deque的首端依次插入。

我这里使用了队列+deque,其实完全可以使用双deque。但是分析过程,就可以发现,用于层序遍历的存储使用队列就可以满足要求。

请注意这里和前面的双栈不同——
前面的双栈都是用来存放当前节点或者子节点的,最后的输出是使用一维vector来存储每一层的遍历结果,使用二维vector来存储最终结果;
而这里的队列是用来存储节点的deque是用来存储每一层的遍历结果,最后使用二维vector来存储输出结果。(因此,最后需要将deque的元素转换成一维vector)。

算法流程:
1)使用队列存储当前节点和子节点;
2)使用deque来存放每一层的遍历结果。

具体实现:

class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>> res2;

        if(root== nullptr)
            return res2;
        int level=1;
        queue<TreeNode*> q;
        deque<int> dq;
        q.push(root);
        while (!q.empty()){
            int qsize=q.size();
            dq.clear();
            for(int i=0;i<qsize;++i){
                TreeNode* cur=q.front();
                //根据奇偶性决定每一层遍历结果的顺序
                level%2!=0 ? dq.push_back(cur->val) : dq.push_front(cur->val);
                q.pop();

                if(cur->left!= nullptr)
                    q.push(cur->left);
                if(cur->right!=nullptr)
                    q.push(cur->right);
            }
            level++;
            vector<int> res1(dq.begin(),dq.end());
            res2.push_back(res1);
        }
        return res2;
    }
};

参考:
面试题32 - III. 从上到下打印二叉树 III(层序遍历 BFS / 双端队列,清晰图解)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值