LeetCode N叉树的前序遍历

题目

  给定一个 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加入输出序列即可。

复杂度分析

  因为需要遍历每一个节点,所以时间复杂度为 O ( N ) O \left( N \right) 。空间上在树只有单节点时复杂度最差为 O ( N ) O \left( N \right) ,平均情况为 O ( l o g N ) O \left( logN \right)

迭代实现( 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
基本思路

  如果是正序将子节点压入栈的话,情况会很复杂,需要记录当前压入栈的是第几个子节点。那么换种思路,将子节点逆序压入栈中,这样就可以一次性将所有子节点都压进栈里,而不需要记录。

复杂度分析

  时间复杂度为 O ( N ) O \left( N \right) 。空间上用了一个栈来实现迭代,不考虑只有根节点的极端情况,满T叉树时栈的最大深度为倒数第二层的节点数量+2,倒数第二层节点数量为 T k 2 T^{k-2} (k为总层数),树的总节点数为 1 T k 1 T \frac{1-T^k}{1-T} ,两者相除,可以得出空间复杂度为 O ( N ) O \left( N\right)
  是不是求得太麻烦了…倒数第二层的节点基本上接近总节点数的 1 T + 1 \frac{1}{T + 1}

优化

来看看别人家的代码

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%左右

  接着看如何对类型为listchildren进行逆序压栈:

q += [child for child in node.children[::-1] if child]

  这是一种方式,但是效率不高,我们可以看另外的对列表进行反向的方法reversed:

q += reversed(node.children)

  这种方式会返回一个list倒序后的generator,效率比[::-1]高很多,有时能达到两三倍。这里加号也可以改成extend()函数,但效率差不多。

参考资料

  1. Python中and(逻辑与)计算法则
  2. Python3 reversed 函数

猜你喜欢

转载自blog.csdn.net/disguise666/article/details/89287390