题目
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,任何两个节点之间都存在距离,返回整棵二叉树的最大距离。
- 最大距离与x无关
左最大距离和右最大距离取max - 最大距离与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)