题目
给定一个 N 叉树,返回其节点值的后序遍历。
示例
给定一个三叉树:
1
/ | \
3 2 4
/ \
5 6
返回其后序遍历: [5,6,3,2,4,1]
解法
递归( Python )
class Solution:
def __init__(self):
self.res = []
def postorder(self, root: 'Node') -> List[int]:
if(root == None):
return []
for node in root.children:
self.postorder(node)
self.res.append(root.val)
return self.res
基本思路
本质上,先序遍历和后序遍历访问节点的顺序是相同的,只是将val
加入到res
的时机不同。先序遍历在访问子节点前就将val
放入res
,但是后序遍历在访问完子节点之后才将val
放入res
。
复杂度分析
因为需要遍历每一个节点,所以时间复杂度为 O ( N ) O \left( N \right) O(N)。空间上在树只有单节点时复杂度最差为 O ( N ) O \left( N \right) O(N),满T叉树时为 O ( l o g T N ) O \left( log_TN \right) O(logTN)。
迭代实现( Python )
class Solution:
def postorder(self, root: 'Node') -> List[int]:
res, n_stack = [], root and [root]
while n_stack:
node = n_stack.pop()
res.append(node.val)
n_stack += node.children
res.reverse()
return res
基本思路
后序遍历实际上可以从右至左的先序遍历来实现。先序遍历的输出顺序是根-左-右
,后序遍历是左-右-根
,那么如果把先序遍历从左至右访问孩子节点的顺序改成从右至左,变成根-右-左
,再逆序输出,是不是就和后序遍历一样了?
复杂度分析
时间复杂度为 O ( N ) O \left( N \right) O(N)。空间上用了一个栈来实现迭代,不考虑只有根节点的极端情况,满T叉树时栈的最大深度为倒数第二层的节点数量+T-1,倒数第二层节点数量为 T k − 2 T^{k-2} Tk−2(k为总层数),树的总节点数为 1 − T k 1 − T \frac{1-T^k}{1-T} 1−T1−Tk,两者相除,可以得出空间复杂度为 O ( N ) O \left( N\right) O(N)。
双栈 ( Java )
class Solution {
public List<Integer> postorder(Node root) {
List<Integer> list = new ArrayList<Integer>();
if(root == null) return list;
Stack<Node> stack1 = new Stack<>();
Stack<Node> stack2 = new Stack<>();
stack1.add(root);
while(!stack1.empty())
{
Node top = stack1.pop();
stack2.push(top);
for(int i = 0; i < top.children.size(); i++)
stack1.push(top.children.get(i));
}
while(!stack2.empty())
list.add(stack2.pop().val);
return list;
}
}
基本思路
本质上和上一种方法相同,还是从右至左的先序遍历。不同之处在于,前一种方法是最后对List
进行reverse
,而这里使用第二个栈后进先出的特点来实现这一功能。
复杂度分析
时间复杂度为
O
(
N
)
O \left( N \right)
O(N)。空间上不仅有类似于上一种方法中栈的stack1
,还有保存所有节点的stack2
,所以空间复杂度为
O
(
N
)
O \left( N \right)
O(N)。