Leetcode-python-二叉树的遍历

题目来自Leetcoode,引用了一些题解和评论里面的代码翻译成了Python·。如有侵权,请联系。

二叉树的前序遍历 

       144. 二叉树的前序遍历

递归写法:

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def preorderTraversal(self, root: TreeNode) -> List[int]:
        L = []
        if not root:return []
        
        def t(node):
            L.append(node.val) 
            if node.left:
                t(node.left)
            if node.right :
                t(node.right)
        t(root)
        return L

非递归的写法:

class Solution:
    def preorderTraversal(self, root: TreeNode) -> List[int]:
        if not root:return []
        stack = [root]
        L = []
        while(stack):
            Q = stack.pop(-1)
            L.append(Q.val)
            if Q.right:    ######注意是先right后left
                stack.append(Q.right)
            if Q.left:
                stack.append(Q.left)
        return L

        # 另外一种
        if not root:return []
        s = []
        ans = []
        node = root
        while(node or s):
            while(node):
                ans.append(node.val) # 存根节点
                s.append(node)       # 为了判断右子树
                node = node.left     # 直到最左子树
            node = s[-1].right       # 最左子树的右子树
            s.pop()
        return ans
    

注意利用栈去存节点的时候,先right后left。因为栈是先进后出的,如果[left,right] => pop() => [right,left]所以要先存right。

二叉树的中序遍历

        94. 二叉树的中序遍历

递归版本

class Solution:
    def inorderTraversal(self, root: TreeNode) -> List[int]:
        if not root:return []
        L = []
        def t(node):
            if node.left:
                t(node.left)
            L.append(node.val)
            if node.right:
                t(node.right) 
        t(root)
        return L

非递归版本(迭代) 代码来自此处@weih1121

# 中序遍历 先遍历左子树->根节点->右子树
# 如果是递归做法则递归遍历左子树,访问根节点,递归遍历右子树
# 非递归过程即:先访问..最左子树..结点,再访问其父节点,再访问其兄弟
# while循环条件 中序遍历需先判断当前结点是否存在,若存在则将该节点放入栈中,再将当前结点设置为结点的左孩子,
# 若不存在则取栈顶元素[最左节点]为cur,在访问cur的右节点。
# 当且仅当栈空cur也为空,循环结束。
class Solution:
    def inorderTraversal(self, root: TreeNode) -> List[int]:        
        if not root:return []
        s = []
        v = []
        node = root
        while(node or s):
            if node : 
                s.append(node)
                node = node.left
            else:
                node = s.pop(-1) # 最后一个
                v.append(node.val)
                node  = node.right
        return v 

二叉树的后序遍历 

       145. 二叉树的后序遍历

递归版本

class Solution:
    def postorderTraversal(self, root: TreeNode) -> List[int]:
        if not root:return []
        L = []
        def t(node):
            if node.left:
                t(node.left)
            if node.right:
                t(node.right) 
            L.append(node.val)
        t(root)
        return L

非递归版本

(1)输出层次遍历的逆

class Solution(object):
    def postorderTraversal(self, root):
        # 层次遍历从左到右,从上到下 -> 队列
        # 深度遍历从左到右,从下到上 -> 栈
        # 栈:根->左->右
        # output:根->右->左 层次不会变
        # output[::-1]:左->右->根

        if root is None:
            return []

        stack, output = [root, ], []
        while stack:
            print([node.val for node in stack])
            root = stack.pop()

            output.append(root.val)
            if root.left is not None:
                stack.append(root.left)
            if root.right is not None:
                stack.append(root.right)          
        return output[::-1]

(2)利用pre判断右节点是否被输出,从左到右的去遍历。来自此处

        if not root: return []
        s,v = [],[]
        cur = root
        pre = None

        while(cur or s):
            while(cur):
                s.append(cur)
                cur=cur.left ##遍历左子树
            cur = s[-1]
            if cur.right == None or cur.right == pre: #判断是否该输出结点
                v.append(cur.val)
                s.pop()
                pre = cur
                cur = None
            else:
                cur=cur.right
        return v

二叉树的层次遍历

          (1)107. 二叉树的层次遍历 II   (2)199. 二叉树的右视图

if not root:return []
q = [root]
L = []
while(q):
    node=q.pop(0) #队列,先进先出
    L.append(node.val)
    if node.left:
        q.append(node.left)
    if node.right:
        q.append(node.right)
return L

二叉树的深度 统计

(1)面试题55 - I. 二叉树的深度  (2) 104. 二叉树的最大深度  (3) 剑指 Offer 55 - II. 平衡二叉树

递归

class Solution:
    def maxDepth(self, root: TreeNode) -> int:
        
        def t(root): O(N) O(N)
            if not root:
                return 0
            left = t(root.left)+1
            right = t(root.right)+1
            return left if left>right else right
        depth = t(root)
        return depth
        
        def depth(root): ## 第二种不同方式的 
            if not root:return 0
            return max(depth(root.left),depth(root.right))+1
        return depth(root)

非递归(层次遍历的层数)

class Solution:
    def maxDepth(self, root: TreeNode) -> int:        
        # 层次遍历的层数 O(N) O(N)
        if not root:return 0
        q = [root]
        ans = 0
        while(q):
            ans +=1
            size = len(q)
            for i in range(0,size):
                node = q.pop(0)
                if node.left:
                    q.append(node.left)
                if node.right:
                    q.append(node.right) 
        return ans

(3)平衡二叉树

解决方法1:计算每棵树的左右子树高度差,当每一层都满足平衡二叉树时,返回Ture,否则返回False

时间复杂度分析:最坏情况是“满二叉树”时,那么每层节点访问 O(logN)。每一层的每个节点都要进行一次深度计算,那么第一层是 N*1,(N-1)/2 *2,...,1*N。最坏的情况就是要调用N次depth函数。故最终时间复杂度是O(NlogN)。补完全二叉树

空间复杂度:O(N),最坏退化到链表,系统需要使用O(N)的栈空间。

class Solution:
    def isBalanced(self, root: TreeNode) -> bool:
        
        def find_depth(root):
            if not root:return 0  ## 深度 返回深度 
             
            left = find_depth(root.left)+1
            right = find_depth(root.right)+1
            return left if left>right else right
        
        def judge(root):
            if not root:return True  ## 判断真假 ,return True or False 
            left = find_depth(root.left)
            right = find_depth(root.right)
            if abs(left-right)>1:
                return False
            return judge(root.left) and judge(root.right) ## 左右都要平衡
        return judge(root) 

解法二:利用后序遍历+剪枝。题解链接

        def judge(root):
            if not root:return 0
            left = judge(root.left) # 先找左子树
            if left == -1:return -1 ## 体现剪枝 
            right = judge(root.right) # 找右子树 
            if right == -1:return -1 
            return max(left,right)+1 if abs(left-right)<=1 else -1 ## 根节点情况 
        return judge(root) != -1  

二叉树的单条路径

        输出二叉树的中的每条路径。例子:

                                                                                      

class Solution:
    def pathSum(self, root: TreeNode, sum_: int) -> List[List[int]]:
        # DFS,找出所有路径 
        L = []
        def find_all_path(root,path):
            if not root:return
            path.append(root.val)
            if not root.left or not root.right :
                L.append(path.copy()) 
                ## 深浅拷贝问题,如果不利用copy(),那么path改变L中的path也会改变
            find_all_path(root.left,path)
            find_all_path(root.right,path)
            path.pop() 
            ## 回溯点,当递归到 node(7)时,find_all_path(left,right)均return,
            ## 此时 path = [5,4,11,7] 向上回溯时,将7删掉,否则 node(2)分支,return[5,4,11,7,2]
        find_all_path(root,[])
        return L

output:[[5,4],[5,4,11,7],[5,4,11,2],[5,8,13],[5,8,4,5],[5,8,4,1]]

        与其相关的题目   剑指 Offer 34. 二叉树中和为某一值的路

上面这个题,可以用于筛选所有分支。可以在上面代码的基础上,添加:

        ans = [] 
        for nums in L :
            if sum(nums) == sum_:
                ans.append(nums)
        return ans 

也可以将sum_加在DFS里面。两篇比较好的解释:链接1链接2.(下面代码参考了链接2)

class Solution:
    def pathSum(self, root: TreeNode, sum_: int) -> List[List[int]]:
        # DFS,找出所有路径 
        L = []
        def find_all_path(root,path,sum_):
            if not root:return
            path.append(root.val)
            if sum_ == root.val and not root.left and not root.right :
                L.append(path.copy()) ## 深浅拷贝问题 
            find_all_path(root.left,path,sum_-root.val) ## 每次都把root.val的值减掉
            find_all_path(root.right,path,sum_-root.val)
            path.pop() ## 回溯点
        find_all_path(root,[],sum_)
        return L

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Foneone

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值