145. 二叉树的后序遍历
力扣题目链接[1]
给你一棵二叉树的根节点 root
,返回其节点值的 「后序遍历」 。
示例1:
代码语言:javascript复制输入:root = [1,null,2,3]
输出:[3,2,1]
「提示:」
- 树中节点的数目在范围
[0, 100]
内 100 <= Node.val <= 100
进阶:递归算法很简单,你可以通过迭代算法完成吗?
思路:
与二叉树的前序遍历和中序遍历一样,我们先写递归版本,再看迭代版本。
递归
写过前序和中序遍历的递归,想必后序遍历也不在话下。需要注意将节点的值放入结果数组的顺序。
代码语言:javascript复制/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @return {number[]}
*/
var postorderTraversal = function(root) {
let result = [];
const postOrder = (root) => {
if (!root) return;
postOrder(root.left);
postOrder(root.right);
result.push(root.val);
}
postOrder(root);
return result;
};
迭代
后序遍历的迭代版本跟前序遍历的很相似。不同之处在于如何放入栈以及放入结果数组中。
后序遍历的顺序是「左右根」,而前序遍历的顺序是「根左右」。我们这里使用unshift
就可以实现前序遍历的逆序,也就是「右左根」。而实现最终「左右根」的效果,只需要将入栈顺序调整一下即可。先将左子节点入栈,再将右子节点入栈。然后出栈的时候,就是根节点、右子节点、左子节点的顺序。依次从头部放入结果数组中。
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @return {number[]}
*/
var postorderTraversal = function(root) {
let result = [];
let stack = [];
if (root) stack.push(root);
while(stack.length) {
const root = stack.pop();
result.unshift(root.val);
if (root.left) stack.push(root.left);
if (root.right) stack.push(root.right);
}
return result;
};
总结
我们通过连续三天的题解来分析了二叉树的前中后序遍历。同时介绍了递归和迭代两种方式。通过比较可以发现,递归的思路都是相同的,唯一不同之处在于将节点的值放入结果数组的时机。
而迭代都采用了栈的方式来实现,其中前序和后序遍历的迭代方式是类似的,不同之处在于放入结果数组的方式,以及左右子节点放入栈中的顺序。中序遍历比较特殊,需要不断寻找左子节点,直到找不到为止。只有这样才能达到左中右的顺序。
参考资料
[1]
力扣题目链接: https://leetcode-cn.com/problems/binary-tree-postorder-traversal/