Leetcode 145:二叉树的后序遍历(最详细的解法!!!)

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

示例:

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

输出: [3,2,1]

进阶: 递归算法很简单,你可以通过迭代算法完成吗?

解题思路

这是一个基础问题,我们参考之前的两个问题

Leetcode 144:二叉树的前序遍历(最优雅的解法!!!)

Leetcode 94:二叉树的中序遍历(最优雅的解法!!!)

class Solution:
    def __init__(self):
        self.ret = []
        
    def postorderTraversal(self, root):
        """
        :type root: TreeNode
        :rtype: List[int]
        """
        if root != None:
            self.postorderTraversal(root.left)
            self.postorderTraversal(root.right)
            self.ret.append(root.val)
            
            
        return self.ret

如果我们使用非递归的方法要怎么做呢?我们实际上可以模拟栈的操作。对于这个问题,实际上在计算机中是这样处理的。我们首先将打印node1.val访问node1的right访问node1的left压入栈中。

stack : cout1   go-1-R   go-1-L

然后弹出访问node1的left,我们发现它是空,所以什么都不操作。接着我们访问node1的right

stack : cout1   cout2   go-2-R   go-2-L   

然后弹出go-2-L,我们接着将打印node3.val访问node3的right访问node3的left压入栈中。

stack : cout1   cout2   go-2-R   cout3   go-3-R   go-3-L 

接着就是弹出这些指令就可以了。

以下伪代码写法是符合的本意的写法:

while len(stack) != 0:
    top = stack.pop()
    if top == cout操作:
        result.append(top.val)
        continue
    if top.right != None:
        stack.append(top.right)
    if top.left != None:
        stack.append(top.left)
    stack.append(cout操作)

但是我们想要表述这种cout操作,我们就不得不使用一些较复杂的数据结构,这是我们不希望看到的。我们有没有更好的做法呢?这个问题的困难的地方在于,我们要保证左右孩子都被访问过了,才访问该节点,这要怎么操作?

对于一个节点p,如果p没有左右孩子,我们直接cout p.val,如果p有左右孩子,我们分别加入中即可。

我们根据上述思路,可以很容易地写出下面的代码:

class Solution:
    def postorderTraversal(self, root):
        """
        :type root: TreeNode
        :rtype: List[int]
        """
        result = list()
        if root == None:
            return result
        
        stack = list()
        stack.append(root)
        while len(stack) != 0:
            top = stack.pop()
            if top.left != None:
                stack.append(top.left)
            if top.right != None:
                stack.append(top.right)

            result.append(top.val)
                
        return result

但是这样写是错的,你如果还记得前序遍历的话,你会发现这和之前的写法很相似Leetcode 144:二叉树的前序遍历(最优雅的解法!!!) 不同地方在于先push right还是push left。这种错误发生的原因在于没有正确理解cout操作是什么时候添加的。当然这里我们的答案很接近了,我们只要reverse一下结果,就是正确答案。所以我们可以这样写

class Solution:
    def postorderTraversal(self, root):
        """
        :type root: TreeNode
        :rtype: List[int]
        """
        result = list()
        if root == None:
            return result
        
        stack = list()
        stack.append(root)
        while len(stack) != 0:
            top = stack.pop()
            if top.left != None:
                stack.append(top.left)
            if top.right != None:
                stack.append(top.right)

            result.insert(0, top.val)
                
        return result

当然我们也可以参考中序遍历的思路,想出这样的解法

  • 如果root不为空,我们将cout操作压栈,同时我们一同压入root,并且更新root=root.right,这样right会和cout操作一直做压栈操作。
  • 当我们发现right为空的时候,我们接着访问栈顶node的left,接着回到第一步。
  • 直到len(stack)==0,我们就结束了。
class Solution:
    def postorderTraversal(self, root):
        """
        :type root: TreeNode
        :rtype: List[int]
        """
        result = list()
        if root == None:
            return result
        
        stack = list()
        while stack or root:
            if root:
                stack.append(root)
                result.insert(0, root.val)
                root = root.right
            else:
                node = stack.pop()
                root = node.left
                
        return result

我将该问题的其他语言版本添加到了我的GitHub Leetcode

如有问题,希望大家指出!!!

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值