145. 二叉树的后序遍历

给定一个二叉树,返回它的 后序 遍历。

示例:

输入: [1,null,2,3]  
   1
    \
     2
    /
   3 

输出: [3,2,1]

class Solution {
public:
    void postorder(TreeNode * root, vector<int> &res) {
        if(!root) return;
        postorder(root->left, res);
        postorder(root->right, res);
        res.push_back(root->val);
    }
    vector<int> postorderTraversal(TreeNode* root) {
        vector<int>res;
        postorder(root, res);
        return res;
    }
};

 

二叉树前中后序的递归版本属于easy题,而迭代版本通常是medium甚至是hard。

在做迭代版本之前,我建议大家先问问各类“遍历”算法的本质是什么?是最后输出的那一串有序的数字吗?数字的顺序是对的,遍历算法就是对的吗?

个人认为,以上问题的答案都应该是:否。“遍历”的本质是对内存的有序访问,失去了访问顺序,即便你用各种数据结构恢复了这个次序,遍历本身也显得毫无意义。常见的后序遍历写法中有一种已经出现在评论区了——它的思想也很简单,大家做过单词串翻转吗?

String in  = "it is a word"
String out = "word a is it"

这个问题有一种很优雅的写法是先reverse(in),然后再逐词翻转——“两次反转”,最后得到的就是正确顺序。

回到二叉树后序遍历,你也可以利用这种思想,利用双向链表的addFirst,对外部次序和内含次序进行同时翻转,同样会得到一种非常”优雅”的解法,结构简单明晰,甚至还有点好背(狗头)。但是,它并没有真正实现“遍历”——仔细看会发现,该算法其实在使用一种异构的前序遍历:“中->右->左”,而非传统意义上的“中->左->右”,而这种异构也正是他的第一次反转。而第二次反转就在输出序列上。

所以本质上,这是一个“前序遍历”,而不是所谓的“后序遍历”。只有当你的各个节点以“左->右->中”的次序依次出现在迭代的loop当中时,它才是真正的后序遍历,就像官解那样。贴个我个人的版本。

class Solution {
public:
    void postorder(TreeNode* root, stack<int> &s){
        if(!root) return;
        s.push(root->val);
        postorder(root->right, s);
        postorder(root->left, s);
    }
    vector<int> postorderTraversal(TreeNode* root) {
        stack<int>s;
        vector<int>res;
        postorder(root, s);
        while(!s.empty())
        {
            res.push_back(s.top());
            s.pop();
        }
        return res;
    }
};

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值