二叉树形冲突分解算法仿真_二叉树 Binary Tree in Python (1)

题源:LeetCode 图源:VisuAlgo

这篇文章汇总了数据结构二叉树 (Binary Tree) 相关问题的多种解法。针对简单题目

equation?tex=%5Ccolor%7Bgreen%7D%7B%28Easy%29%7D ,讨论的重点倾向于对Python编程知识的活学活用,和思路的发散与实现。

26ef81d5d7465c9120895570bba616b2.gif
算法示意图来源:VisuAlgo - Binary Search Tree

目录

1 / 二叉树的最大深度

equation?tex=%5Ccolor%7Bgreen%7D%7B+%28Easy%29%7D

2 / 平衡二叉树

equation?tex=%5Ccolor%7Bgreen%7D%7B+%28Easy%29%7D

3 / 二叉树中的最大路径和

equation?tex=%5Ccolor%7Bred%7D%7B%5C%2C%28Hard%29%7D

1 / 二叉树的最大深度

equation?tex=%5Ccolor%7Bgreen%7D%7B+%28Easy%29%7D

-- 问题描述

给定一个二叉树,找出其最大深度。二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。

说明: 叶子节点是指没有子节点的节点。

示例:

给定二叉树 [3,9,20,null,null,15,7]。

    3
   / 
  9  20
    /  
   15   7

输入:[3,9,20,null,null,15,7]
输出:3

Python题目提供信息:

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right

-- 解法一

☔️ List + None元素标记不同层(子父节点)

List 是实现Tree的最近暗淡的数据结构,但容易导致新加入元素难辨处于何种位置。(比如,究竟是右节点呢,还是下一层的节点?)

因此,用List实现时,我们完全模拟输入列表信息,用None划分不同层级。

if cur_node: ... elif queue: ... 排除了达到队列尾端queue为None的情况,确指「仅元素为None时」,即到达分层位置。

class Solution:
    def maxDepth(self, root: TreeNode) -> int:
        if not root: return 0
        
        # Use a None to mark a level (increase depth)         
        queue = [root, None]
        depth = 1
        
        while queue:
            # Pop out the current node, and append its children
            cur_node = queue.pop(0)
            
            if cur_node:
                if cur_node.left: queue.append(cur_node.left)
                if cur_node.right: queue.append(cur_node.right)
            elif queue:
                # Mark a new level
                queue.append(None) 
                depth += 1
        
        return depth

-- 解法二

☔️ BFS广度优先搜索,使用双端队列 deque()

加入内层循环后,遍历同层节点以添加下一层节点,但不做depth的增加。多了一层循环,但每个节点只访问了一次,时间复杂度还是

equation?tex=O%28n%29
import collections

class Solution:
    def maxDepth(self, root: TreeNode) -> int:
        if not root: return 0
               
        queue = collections.deque()
        queue.append(root)
        depth = 0
        
        while queue:
            depth += 1  
            
            # Only iterate through nodes from the same level
            for _ in range(len(queue)):
                cur_node = queue.popleft()    
                
                if cur_node.left: 
                    queue.append(cur_node.left)
                if cur_node.right: 
                    queue.append(cur_node.right)
            
        return depth

-- 解法三

☔️ DFS深度优先搜索,使用递归

import collections

class Solution:
    def maxDepth(self, root: TreeNode) -> int:
        if not root: return 0  

        self.depth = 0
        self._depthFirstSearch(root, 0) 

        return self.depth
    
    
    def _depthFirstSearch(self, node: TreeNode, level: int):
        if not node: return  
 
        if self.depth < level + 1:
            self.depth = level + 1  

        self._depthFirstSearch(node.left, level + 1)
        self._depthFirstSearch(node.right, level + 1)

-- 解法四

☔️ DFS深度优先搜索 + 分治算法,使用递归

分治法 (Devide-and-Conquer) 的工作原理是将问题递归 分解为两个或多个相同或相关类型的子问题,直到这些子问题变得足够简单以至于可以直接解决。然后将子问题的解决方案组合起来,以解决原始问题。
利用分治法解决问题有下面三个步骤:
1. 分解:将原问题分解为多个子问题,每个子问题与原问题类型相同,但比原问题规模小。
2. 解决:递归求解子问题,如果子问题规模足够小,直接可以求解。
3. 合并:合并子问题的解,得到原问题的解。

—— 黄哥Python:分治算法

class Solution:
    def maxDepth(self, root: TreeNode) -> int:
        if not root: return 0  
        
        return 1 + max(self.maxDepth(root.left),
                       self.maxDepth(root.right))

2 / 平衡二叉树

equation?tex=%5Ccolor%7Bgreen%7D%7B%28Easy%29%7D

-- 问题描述

给定一个二叉树,判断它是否是高度平衡的二叉树。

一棵高度平衡二叉树定义为:一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。

示例:

18fbe166b1a03db2078243aa05c9e3bf.png
输入:root = [1,2,2,3,3,null,null,4,4]
输出:false

-- 解法一:递归

对于满足条件就返回某值的计数类问题,写递归时可能以为不满足条件返回False与int的数据类型冲突。此时,通常用-1标记不满足条件的情况。

class Solution:
    def isBalanced(self, root: TreeNode) -> bool:
        if not root: return True
        
        return self._countHight(root) >= 0
        
    
    def _countHight(self, node: TreeNode) -> int:
        if not node: return 0
        
        lh = self._countHight(node.left)
        rh = self._countHight(node.right)
        
        if lh >= 0 and rh >= 0 and abs(lh - rh) <= 1:
            return max(lh, rh) + 1
        else:
            return -1

3 / 二叉树中的最大路径和

equation?tex=%5Ccolor%7Bred%7D%7B%28Hard%29%7D

-- 问题描述

给你一个二叉树的根节点 root ,返回其最大路径和。

本题中,路径被定义为一条从树中任意节点出发,沿父节点-子节点连接,达到任意节点的序列。该路径 至少包含一个 节点,且不一定经过根节点。

示例 1:

a01663b0b15f669480fe6a17e4e144f4.png
输入:root = [1,2,3]
输出:6

-- 解法一:递归

一个在最长路径上的节点只可能处于两种情况:

1. 位于最长路径的根节点,

node.leftnode.right均在路径中)。

2. 位于最长路径上的某子节点,

node的父节点同样在路径中)。

  • 第一种情况,可能构成最大路径的路径有:
    • 当前节点(左右字数路径值均为负);
    • 当前节点 + 左子树;
    • 当前节点 + 右子树;
    • 当前节点 + 左子树 + 右子树。

我们将上述四种最大情况的cur_max与当前最长路径之作比较,并适时直接替换最长路径和self.maxSum(无需迭代增值)。

  • 第二种情况,可能构成最大路径的路径有:
    • 当前节点(左右字数路径值均为负);
    • 当前节点 + 左子树;
    • 当前节点 + 右子树。

因为这种情况假设的是父节点一定位于最大路径,所以不能同时包含左右子树。

该最大和值需通过递归向父节点传递并叠加。

本题重点是明确节点可能处于的各种情况,分情况做实现。

class Solution:
    def maxPathSum(self, root: TreeNode) -> int:
        if not root: return 0
        
        self.maxSum = -sys.maxsize - 1
        self._findPath(root)
        
        return self.maxSum
        
        
    def _findPath(self, node: TreeNode) -> int:
        if not node: return 0
        
        lm = self._findPath(node.left)
        rm = self._findPath(node.right)
        cur_max = node.val + max(0, lm, rm, lm + rm)
        self.maxSum = max(self.maxSum, cur_max)
        
        return node.val + max(0, lm, rm)

9ecd2d8c64d1869672aaae2b713e7346.gif
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值