题目
给定一个 N 叉树,返回其节点值的前序遍历。
示例
给定一个三叉树:
1
/ | \
3 2 4
/ \
5 6
返回其前序遍历:[1,3,5,6,2,4]
解法
递归实现( Python )
"""
# Definition for a Node.
class Node:
def __init__(self, val, children):
self.val = val
self.children = children
"""
class Solution:
def __init__(self):
self.res = []
def preorder(self, root: 'Node') -> List[int]:
if(root == None):
return []
self.res.append(root.val)
for node in root.children:
self.preorder(node)
return self.res
基本思路
递归法很简单,先确定基准情形root == None
,然后在遍历每个子节点之前将本身的val
加入输出序列即可。
复杂度分析
因为需要遍历每一个节点,所以时间复杂度为 。空间上在树只有单节点时复杂度最差为 ,平均情况为 。
迭代实现( Python )
class Solution:
def preorder(self, root: 'Node') -> List[int]:
if root == None:
return []
res = []
n_stack = [root]
while(n_stack != []):
node = n_stack.pop()
res.append(node.val)
for i in range(1, len(node.children) + 1):
n_stack.append(node.children[-i])
return res
基本思路
如果是正序将子节点压入栈的话,情况会很复杂,需要记录当前压入栈的是第几个子节点。那么换种思路,将子节点逆序压入栈中,这样就可以一次性将所有子节点都压进栈里,而不需要记录。
复杂度分析
时间复杂度为
。空间上用了一个栈来实现迭代,不考虑只有根节点的极端情况,满T叉树时栈的最大深度为倒数第二层的节点数量+2,倒数第二层节点数量为
(k为总层数),树的总节点数为
,两者相除,可以得出空间复杂度为
。
是不是求得太麻烦了…倒数第二层的节点基本上接近总节点数的
。
优化
来看看别人家的代码
class Solution(object):
def preorder(self, root):
ret, q = [], root and [root]
while q:
node = q.pop()
ret.append(node.val)
q += [child for child in node.children[::-1] if child]
return ret
首先看第一行:
ret, q = [], root and [root]
我一直以为and
返回的是True
或者False
,然而并不是这样。这里如果root
为None,则返回root
;如果root
和[root]
都为真,那么返回的是[root]
。补充一句,运算符or
也有类似机制。这么写比我用if
语句判断要快20%~30%左右。
接着看如何对类型为list
的children
进行逆序压栈:
q += [child for child in node.children[::-1] if child]
这是一种方式,但是效率不高,我们可以看另外的对列表进行反向的方法reversed
:
q += reversed(node.children)
这种方式会返回一个list
倒序后的generator
,效率比[::-1]
高很多,有时能达到两三倍。这里加号也可以改成extend()
函数,但效率差不多。