给定一个二叉树,返回它的 后序 遍历。
示例:
输入: [1,null,2,3]
1
\
2
/
3
输出: [3,2,1]
进阶: 递归算法很简单,你可以通过迭代算法完成吗?
解题思路
这是一个基础问题,我们参考之前的两个问题
Leetcode 144:二叉树的前序遍历(最优雅的解法!!!)
Leetcode 94:二叉树的中序遍历(最优雅的解法!!!)
class Solution:
def __init__(self):
self.ret = []
def inorderTraversal(self, root):
"""
:type root: TreeNode
:rtype: List[int]
"""
if root != None:
self.inorderTraversal(root.left)
self.ret.append(root.val)
self.inorderTraversal(root.right)
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
如有问题,希望大家指出!!!