python_8_二叉树递归

题目

1 得到后继节点(特殊树)

二叉树结构如下定义:

class Node:
    def __init__(self,value):
        self.value = value
        self.left = None
        self.right = None
        self.parent = None     # 指向父的指针

class Tree:
    def __init__(self):
        self.root = Node(None)

    def get_successorNode(self,node):
        if not node:
            return node
        if node.right:        # 右孩子不为空,有右树
            return self.getLeftMost(node.right)   # 找到右树上的最左节点
        else:                 # 无右树
            parent = node.parent     # 将node的父节点找出来
            while parent and parent.left != node:        # 当前节点是父节点的右孩子
                node = parent
                parent = node.parent               # 只要是父的右孩子就往上直到我是我父节点的左孩子
            return parent                          # 返回父节点,返回空是给你的节点是整棵树最右节点

    def getLeftMost(self,node):
        if not node:
            return node
        while node.left:   # 不断的往左
            node = node.left
        return node        # 返回最左的节点

2 打印树的中序遍历

在这里插入图片描述

打印树的中序遍历就是这么一道题,不需要建立整棵树

    def printAllFolds(self,N):   # 拿递归过程模拟了树,但并没有建树
        self.printProcess(1,N,True)   # i=1 从第一层开始,N最多几层,此时的点是不是凹凸,true是第一个结点是凹


    # 递归过程,来到了某一个节点
    # i是节点层数,N是一共几层,down == true 凹       down == false 凸
    def printProcess(self,i,N,down):
        if i > N:
            return
        self.printProcess(i+1,N,True)  # 2凹,3凹
        if down == True:
            print("凹")
        else:
            print("凸")
        self.printProcess(i+1,N,False)

3 二叉树的递归套路

在这里插入图片描述
可以解决绝大多数的二叉树问题,尤其是树型dp问题
本质是利用递归遍历二叉树的便利性
给一个节点,潜台词:知道左子树信息,知道右子树信息

class Node:
    def __init__(self,value):
        self.value = value
        self.left = None
        self.right = None
        self.parent = None     # 指向父的指针

class Tree:
    def __init__(self):
        self.root = Node(None)


# 左右树要求一样,info 信息返回的结构体
class Info:
    def __init__(self,b,h):
        self.isBalaced = b   # boolean类型
        self.height = h      # 高度

    # X节点返回信息和左右子树返回信息一致,平衡还要自己达标
    def process(self,X):
        if X:     # 空树平衡,返回TRue和高度为0
            return Info(True,0)
        leftInfo = self.process(X.left)  # 左树可以给我信息,给左树是否平衡,左树高度是多少
        rightInfo = self.process(X.right)

        if leftInfo.height >= rightInfo.height:  # 最大的高度加上头结点那一个就是总高度
            height = leftInfo.height + 1
        else:
            height = rightInfo.height + 1
        isBalaced = True                    # 默认整树是平衡
        if leftInfo.height - rightInfo.height < 0:
            cha = rightInfo.height - leftInfo.height
        else:
            cha = leftInfo.height - rightInfo.height
        if not leftInfo.isBalaced or not rightInfo.isBalaced or cha > 1: # 如果左不平,右不平,左右差值大于1,平衡返回false
            isBalaced = False
        return Info(isBalaced,height)

# 主函数调用,树是否平衡
def isBalance(root):
    return Info.process(root).isBalaced

3.1 二叉树的递归套路实践1,两个点最大距离

给定一颗二叉树的头结点head,任何两个节点之间都存在距离,返回整棵二叉树的最大距离。

  1. 最大距离与x无关
    左最大距离和右最大距离取max
  2. 最大距离与x有关
    左树高度+右树高度+1
    解:对左树的要求是,返回整棵树最大距离和高度,右树同理
# 左右树要求一样,info 信息返回的结构体
class Info:
    def __init__(self,dis,h):
        self.maxDistance = dis   # 距离
        self.height = h          # 高度

    def process(self,X):
        if not X:
            return Info(0,0)

        leftInfo = self.process(X.left)      # 知道左树的信息
        rightInfo = self.process(X.right)    # 知道右树信息

        # 接下来要知道当前点的信息,获取当前点的最大高度
        if leftInfo.height >= rightInfo.height:   # 自己点的最大高度
            height = leftInfo.height + 1
        else:
            height = rightInfo.height + 1

        # 获取当前点的最大距离
        if leftInfo.maxDistance >= rightInfo.maxDistance:
            cha = leftInfo.maxDistance
        else:
            cha = rightInfo.maxDistance
        if cha >= leftInfo.height + rightInfo.height + 1:
            maxDistance = cha
        else:
            maxDistance = leftInfo.height + rightInfo.height + 1
            
        return Info(height,maxDistance)

def maxDistance(root):  # 主函数调用,得到最大距离
    return Info.process(root).maxDistance 

3.2 二叉树的递归套路实践2,返回最大的二叉搜索子树的头节点

二叉搜索树:值都不一样,左小右大。最大是指节点个数最大
列可能性:

  • 与x无关(总成立)
    最大儿叉搜索树不是x节点
  • 与x有关(满足下面条件才成立)
    x的左右树都是搜索二叉树,左max小于X的值,右min得大于X的值,才是和x有关

左树需要:

  • 最大搜索二叉子树的大小
  • 左树整体是不是搜索儿叉树
  • 左树上的最大值

右树需要:

  • 最大搜索二叉子树的大小
  • 左树整体是不是搜索儿叉树
  • 右树上的最小值

有两个需要太繁琐,直接集合成子树
子树需要:

  • 最大儿叉搜索子树的大小
  • 整棵树是否为搜索二叉树
  • 整棵树最大值
  • 整棵树最小值
class Node:
    def __init__(self,value):
        self.value = value
        self.left = None
        self.right = None

class Tree:
    def __init__(self):
        self.root = Node(None)

# 任何子树,求了全集
class Info:
    def __init__(self,iss,size,mi,ma):
        self.isAllBST = iss          # 是否为搜索二叉树
        self.maxSubBSTSize = size    # 最大节点个数
        self.min = mi                # 整棵树最大值
        self.max = ma                # 整棵树最小值

    def process(self,X):
        if not X:   # 开始设置4个信息,但最小值最大值不好设置,给不了信息就返回空
            return None    # 如果返回空就需要自己判空,x为空节点什么也返回不了

        # 默认左右树可以给我4个信息
        leftInfo = self.process(X.left)
        rightInfo = self.process(X.right)

        # 然后加自己的信息:isAllBST,maxSubBSTSize,min,max
        # 先处理最好处理的值:max和min
        min = X.value
        max = X.value
        # 如果我左边的信息不是空的
        if leftInfo:    # 左树不空,就能用左树信息,之前收集最小和左树信息最小值比较
            if min > leftInfo.min:
                min = leftInfo.min
            if max < leftInfo.max:
                max = leftInfo.max
        # 右树同理
        if rightInfo:
            if min > rightInfo.min:
                min = rightInfo.min
            if max < rightInfo.max:
                max = rightInfo.max

        # 开始处理剩下两个信息
        maxSubBSTSize = 0
        if leftInfo:         # 左树不为空,那么左树的答案先成为我的答案,情况一考虑完了
            maxSubBSTSize = leftInfo.maxSubBSTSize
        if rightInfo:        # 右树不为空,那么和之前的答案作比较,最大值成为我的答案
            if maxSubBSTSize < rightInfo.maxSubBSTSize:
                maxSubBSTSize = rightInfo.maxSubBSTSize

        isAllBST = False  # 默认False

        # 考虑可能性二
        '''
        if 如果可能性二成立:
            maxSubBSTSize = 以X为头的所有节点数  # 满足二情况,头结点为最大节点,整棵树都是搜索二叉树了

            isAllBST = True
        如果可能性二不成立,那就维持上面的总队,返回就行
        '''
        temp1 = 0
        temp2 = 0
        temp3 = 0
        temp4 = 0
        if not leftInfo:                   # 左树整体需要是搜索二叉树  左树是空必然是搜索二叉树,如果不为空就拿左树信息用
            temp1 = True                   # 左树为空,不影响是搜索二叉树
        else:
            temp1 = leftInfo.isAllBST      # 如果左树不为空,就需要调用isAllBST信息判断是否为二叉搜索树
        if not rightInfo:                  # 右树整体是否满足搜索二叉树
            temp2 = True
        else:
            temp2 = rightInfo.isAllBST
        if not leftInfo:                   # 左树最大值必须小于X节点
            temp3 = True
        else:
            if leftInfo.max < X.value:
                temp3 = True
            else:
                temp3 = False
        if not rightInfo:                   # 右树最小值必须大于X节点
            temp4 = True
        else:
            if rightInfo.min > X.value:
                temp4 = True
            else:
                temp4 = False

        if temp1 and temp2 and temp3 and temp4:    # 符合情况二
            if not leftInfo:
                leftInfo = 0
            else:
                leftInfo = leftInfo.maxSubBSTSize
            if not rightInfo:                      # 只要用信息就需要判空
                rightInfo = 0
            else:
                rightInfo = rightInfo.maxSubBSTSize
            maxSubBSTSize = leftInfo.maxSubBSTSize + rightInfo.maxSubBSTSize + 1
            isAllBST = True

        return Info(isAllBST,maxSubBSTSize,min,max)




3.3 二叉树的递归套路实践3,派对的最大快乐值

员工信息的定义如下:

class Employee:
	def __init__(self):
        self.happy = 0            # 这名员工可以带来的快乐值
        self.subordinates = 0        # 这名员工有哪些直接下级,列表类型

公司的每个员工都符合Employee类的描述。整个公司的人员结构可以看作是一棵标准的、没有环的多叉树。树的头节点是公司唯一的老板。除老板之外的每个员工都有唯一的直接上级。叶节点是没有任何下属的基层员工(subordinates列表为空),除基层员工外,每个员工都有一个或多个直接下级。
在这里插入图片描述
列可能性:

  • 给X节点发
    得到x的快乐值
    需得到下级a,b,c员工不来情况下,a,b,c下整个树的快乐值,和整个树的最大快乐值
    需得到X不来情况下,整个树的最大快乐值
  • 不给X发
    max(a节点来情况下树最大快乐值,a不来整棵树最大快乐值)+max(b节点来情况下树最大快乐值,b不来整棵树最大快乐值)

info信息结构,子节点,需要节点来时快乐总值,节点不来时整棵树快乐总值

class Employee:

    def __init__(self,happy):
        self.happy = happy                      # 这名员工可以带来的快乐值
        self.next = []        # 这名员工有哪些直接下级


class Info:
    def __init__(self,y,n):
        self.yes = y            # 节点来的时候整棵树的最大快乐值
        self.no = n             # 节点不来的时候整棵树最大快乐值

    def process(self,x):
        if x.next.pop is None:   # 如果列表中没有下一个元素了,也就是你是基层员工
            return Info(x.happy,0)      # 来了返回自己的快乐值,如果不来就返回0,yes=happy No=0
        yes = x.happy           # x要来了,先是统计基层员工,也就是叶子节点
        no = 0                  # x不来
        for i in x.next:
            nextInfo = self.process(i)       # 调用每一个基层员工,要来他的信息
            yes = yes + nextInfo.no          # 如果x来了,累加的是每棵子树在头结点不来情况下的快乐最大值
            if nextInfo.yes >= nextInfo.no:  # 如果不来
                no = no + nextInfo.yes
            else:
                no = no + nextInfo.no
        return Info(yes,no)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值