剑指offer - 面试题32扩展: 之字形打印二叉树 - C++

/*
struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) :
            val(x), left(NULL), right(NULL) {
    }
};
*/
class Solution {
public:
    vector<vector<int> > Print(TreeNode* pRoot) {
        vector<vector<int> > result;
        if(pRoot == nullptr) return result; 
        
        stack<TreeNode*> levels[2];
        int current = 0, next = 1;
        levels[current].push(pRoot);
        TreeNode* pNode;
        int depth = 1;
        vector<int> temp;
        result.push_back(temp);
        result[0].push_back(pRoot->val);
        
        while(!levels[current].empty()) {
            
            pNode = levels[current].top();
            levels[current].pop();
            
            if(result.size() < depth+1) {
                vector<int> temp;
                result.push_back(temp);
            }

            if((depth & 0x1) == 1) {
                if(pNode->right != nullptr) {
                    result[depth].push_back(pNode->right->val);
                    levels[next].push(pNode->right);
                }
                if(pNode->left != nullptr) {
                    result[depth].push_back(pNode->left->val);
                    levels[next].push(pNode->left);
                }
            } else {
                if(pNode->left != nullptr) {
                    result[depth].push_back(pNode->left->val);
                    levels[next].push(pNode->left);
                }
                if(pNode->right != nullptr) {
                    result[depth].push_back(pNode->right->val);
                    levels[next].push(pNode->right);
                }
            }
            if(levels[current].empty()) {  // 避免两层循环
                if(result[depth].empty()) {
                    result.pop_back();
                    return result;
                } else {
                    current = 1-current;
                    next = 1-next;
                    depth++;
                }
            }
        }
        return result;
    }
};

这道题确实复杂。

两个重犯小错误:&的优先级小于==,下次判断奇偶要小心;最后忘记return。

这是我借鉴书上的思维写出来的基于循环,吸收了它用一个栈数组来定义两个栈、定义下标为0和1,巧妙交换两个栈的妙用。由于书上是直接打印,所以代码要比书上复杂一些。尤其是最后判断result[depth]是否是空这里,我觉得有点不简洁,但暂时没有其它想法。

以下是我自己琢磨的基于递归写的。

class Solution {
public:
    vector<vector<int> > Print(TreeNode* pRoot) {
        vector<vector<int>> result;
        if (pRoot == nullptr) return result;
             
        vector<int> newLayerVec;
        result.push_back(newLayerVec);
         
        stack<TreeNode*> toolStack;
        result[0].push_back(pRoot->val);
        toolStack.push(pRoot);
         
        handleTheLayer(toolStack, 1, result);  // 按层处理
        return result;
    }
     
    void handleTheLayer(stack<TreeNode*> toolStack, int depth, vector<vector<int>>& result) {
        if(toolStack.empty()) return;
         
        stack<TreeNode*> nextLayerStack;
        vector<int> newLayerVec;
        result.push_back(newLayerVec);
        TreeNode* pNode;
        while(!toolStack.empty()) {
            pNode = toolStack.top();
            toolStack.pop();
            if(depth & 0x1 == 1) {
                if(pNode->right != nullptr) {
                    result[depth].push_back(pNode->right->val);
                    nextLayerStack.push(pNode->right);
                }
                if(pNode->left != nullptr) {
                    result[depth].push_back(pNode->left->val);
                    nextLayerStack.push(pNode->left);
                }
                 
            } else {
               if(pNode->left != nullptr) {
                    result[depth].push_back(pNode->left->val);
                    nextLayerStack.push(pNode->left);
                }
                 if(pNode->right != nullptr) {
                    result[depth].push_back(pNode->right->val);
                    nextLayerStack.push(pNode->right);
                }
            }
        }
        if(!result[depth].size()) {
            result.pop_back();
            return;
        }
         
        handleTheLayer(nextLayerStack, depth+1, result);
    }
};

二刷

感觉这道题挺难的,如果掌握了这道题,那二叉树的各种酷炫魔幻遍历就没有什么问题了,所以回来二刷。

思考的时候,不知道怎样辨别换行,于是看了一下书上,逐行打印的题告诉我说用两个变量记录当前行还剩节点数和下一行节点数,于是翻回去把逐行打印的题做了一下,还算顺利。

然后再回来做之字形打印,把栈改成了队列。做半天调通了发现打印顺序清奇,到书上一看发现做出一个标准错误答案,一个栈是不行的。

于是改成有两个元素的栈数组。做完之后倒是通过编译,但是少打了一行,手动运行代码后知道是判断条件出了问题,修改之后终于通过,代码如下:

class Solution {
public:
    vector<vector<int> > Print(TreeNode* pRoot) {
        vector<vector<int>>  result;
        if(pRoot == nullptr) return result;
  
        stack<TreeNode*> nodes[2];
        int thisLevel = 0;
        int nextLevel = 1 - thisLevel;
          
        bool leftFirst = true;
        nodes[thisLevel].push(pRoot);
        vector<int> currentLevel;
        TreeNode* pNode;
        while(!nodes[thisLevel].empty()) {
            pNode = nodes[thisLevel].top();
            nodes[thisLevel].pop();
            currentLevel.push_back(pNode->val);
            if(leftFirst) {
                if(pNode->left != nullptr) {
                    nodes[nextLevel].push(pNode->left);
                }
                if(pNode->right != nullptr) {
                    nodes[nextLevel].push(pNode->right);
                }
            } else {
                if(pNode->right != nullptr) {
                    nodes[nextLevel].push(pNode->right);
                }
                if(pNode->left != nullptr) {
                    nodes[nextLevel].push(pNode->left);
                }
            }
            if(nodes[thisLevel].empty()) {
                result.push_back(currentLevel);
                currentLevel.clear();
                thisLevel = 1 - thisLevel;
                nextLevel = 1 - thisLevel;
                leftFirst = !leftFirst;
            }
        }
        return result;
    }
};

虽然过程曲折,最后写出的这个代码还是比较满意的。

这道题的关键在于,用栈,且用两个。

表扬一下自己之前写的递归,惊呆,真棒,仿佛不是自己写的

小技巧:两个东西需要交换,用一个有两个元素的数组,交换下标,这样性能好,类似于STL中的swap函数

逐行打印的题也可以用两个队列,但是没必要。它可以用一个队列,用两个变量记录行节点个数就行。

万变不离其宗,其实这道题也借鉴了很多二叉树的前中后序遍历的写法。基础是王道,重复是王道。

关于一刷循环写法的小疑惑在此解决:岀栈时打印,而非入栈打印,避免了先要准备一个空的vector<int>,最后还要删去的情况。其实书上就是这样,当时写完有疑惑之后也没回去看看书,情有可原,写题很累的。编程就是这样,要不断吸收各方的优点,改进代码。

最近有些不顺,腾讯两面两挂,农行简历挂,给自己打个气,坚持走下去!

 

天呐,简洁!我是个天才!

class Solution {
public:
    vector<vector<int> > Print(TreeNode* pRoot) {
        vector<vector<int>> result;
        handleByDepth(pRoot, 1, result);
        return result;
    }
    
    void handleByDepth(TreeNode* pNode,
                           int depth,
                           vector<vector<int>>& result) {
            if (pNode == nullptr) return;
            if(result.size() < depth) {
                vector<int> temp;
                result.push_back(temp);
            }
             if((depth & 0x1) == 1) {
                result[depth-1].push_back(pNode->val);
                
            } else {
                result[depth-1].insert(result[depth-1].begin(), pNode->val);            
            }
            handleByDepth(pNode->left, depth+1, result);
            handleByDepth(pNode->right, depth+1, result);
    }
};

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值