用栈模拟递归形式,值得考虑的是,左子树入栈的时候就先把节点保存好即可。
对应的是
ret.append(root.val)
dfs(root.left)
dfs(root.right)
class Solution:
def preorderTraversal(self, root: TreeNode) -> List[int]:
ret=[]
stk=[]
p=root
while p:
ret.append(p.val)
stk.append(p)
p=p.left
while stk:
t=stk.pop()
r=t.right
while r:
ret.append(r.val)
stk.append(r)
r=r.left
return ret
对于中序遍历,我们要记得形式是:
dfs(root.left)
ret.append(root.val)
dfs(root.right)
也就是说,当左子树递归完毕后再保存节点值,这样很容易在前序遍历的基础上改造出来。
class Solution:
def inorderTraversal(self, root: TreeNode) -> List[int]:
ret=[]
stk=[]
p=root
while p:
stk.append(p)
p=p.left
while stk:
t=stk.pop()
ret.append(t.val)
r=t.right
while r:
stk.append(r)
r=r.left
return ret
方法1:顺序颠倒
考虑后序遍历是左-右-根,前序遍历是根-左-右,如果我们前序遍历改为根-右-左,那么结果再反过来就是左-右-根了。
class Solution:
def postorderTraversal(self, root: TreeNode) -> List[int]:
if not root:
return []
stk=[root]
ret=[]
while stk:
p=stk.pop()
ret.append(p.val)
if p.left:
stk.append(p.left)
if p.right:
stk.append(p.right)
return ret[::-1]
需要注意的是弹出的顺序,因为压栈顺序是先左再右所以弹出是先右再左,最终返回的顺序是反方向的顺序。
方法2:保存一个pre节点
pre节点保存的是遍历过程中的前一个节点,我们为了出栈顺序是先左再右,则先右再左压栈,如果pre是栈顶节点的子节点之一时,说明已经遍历完左子树和右子树了,那么应当加入;除此之外,如果栈顶是一个叶子节点,那么也直接保存即可,因为是不需要考虑压子节点的。
class Solution:
def postorderTraversal(self, root: TreeNode) -> List[int]:
if not root:
return []
ret=[]
stk=[root]
pre=None
while stk:
cur=stk[-1]
if not cur.left and not cur.right or pre and pre in (cur.left,cur.right):
ret.append(cur.val)
pre=stk.pop()
else:
if cur.right:
stk.append(cur.right)
if cur.left:
stk.append(cur.left)
return ret