树的总结(算法)
总的来说树需要掌握的由一下几点:
1、树的遍历方式:前序(根左右),中序(左根右,二叉搜索树中序遍历必有序),后序(左右根),层序(一个列表,多个列表,之字形)
2、树的递归
3、树的迭代(利用栈来实现)
4、树的创建(列表或者是字典)
5、树的动态规划(动态规划里面再讲)
下面就具体的一些题目来说一下。
首先放一下树递归的GIF图(来自leetcode的一个大佬制作的)
上面这个图是递归的基础,必须牢记。
我自己总结了一下相应的树的算法。仅供参考。
代码都是用python3写的,基本上都是leetcode的题目。
这里是代码链接结合代码再看下面的总结会大有帮助的。(可以帮忙点个小星星)
总结:
其实说白了,二叉树也就是4种遍历方式,外加列表存储一下树节点,重要的是弄懂树的递归是怎么一回事。
1、重建二叉树:题目给出的是: 先序+中序 或者是 层序+中序 解题思路:根据题中所给的序列分别构造相应的左右子树序列,然后左右分别递归,注意在递归出口节点创建树节点。
2、树的子结构:解题思路:先判断根节点值是否相等,然后再判断下面的结构是否相等,若根节点值不相等,则判断左子树和右子树是否与子结构相等 子函数(判断树中元素是否相等):子结构为空返回True,树为空返回False,然后判断各个位置的值是否相等。(子函数返回True或者False的,一般递归出现在最后的return条件)
3、二叉树的镜像: 解题思路:交换左右子树的值 然后分别递归左右子树(也就是左右子树分别交换)
4、判断是否是对称的二叉树(也就是镜像二叉树): 解题思路:比较左右子树 子函数:先判断左右子树均为空返回True 有一个为空返回False ,然后再比较根节点的值,若相等接着递归比较左右,右左
5、从上往下打印二叉树: 解题思路:先把数放入列表中,方便索引。 当列表不为空的时候,若根节点存在左节点则把左节点放入树列表的后面,同理右节点也是。然后保存根节点的值,同时pop出根节点。
6、从上往下按行打印二叉树:解题思路:与上面的不同就是要建立一个临时列表list1保存根节点的值,还有建立一个临时列表list2保存子节点的值,循环完根节点列表以后,用临时列表list1保存根节点的值同时把list2中的子节点的值赋值给根节点列表,再次循环。(其实这就是二叉树的层序遍历)
15、之字形打印二叉树: 解题思路:利用一个标志变量flag来标记从左往右还是从右往走,然后就是利用栈和flag=1的时候反向储存节点值,实现。
7、判断数组是否是二叉搜索树的后序遍历序列:解题思路:后续遍历的特点就是最后一个节点是根节点。然后二叉搜索树的特点就是左子树小于根节点的值,右子树大于根节点的值。所以我们的解题思路就是先分割左右子树,然后判断左右子树是否满足二叉搜索树的条件,然后分别递归左右子树。
8、二叉树中和为某一值(k)的路径(路径总和二): 解题思路:先创建一个类变量sum用于存放求和值。再创建一个列表self.a存放路径中的数值。若sum==k且左右子树均为空,self.b.append(self.a[:]),若sum小于k,递归左右子树,否则(大于k)sum -=self.a[-1],self.a.pop()
16、路径总和:因为是返回True或False所以return 递归。
9、二叉搜索树转化为双向链表: 解题思路:先递归转化左子树,在把左子树的最右边一个节点链接到根节点上(双向链接),同理右子树,然后从根节点向前寻找头结点,返回头结点的地址
24、二叉树展开为链表:先找到左子树的最右边节点,然后将右节点挂在左子树的最右边节点上,最后再把整个左子树挂在根节点的右边。然后后序遍历二叉树。
10、二叉树的最大深度: 解题思路:(1)后序遍历,返回左右子树的最大值+1 (2)按层向下检索,与2,5相似
23、二叉树的最小深度:与上相似,区别在于添加一个判断左节点或右节点为空,然后返回left+right+1.
11、平衡二叉树: 解题思路:后序遍历,判断左右子树长度差。(这里有一个编程小技巧,建立一个类变量,用于子函数在递归过程中返回True或False。满足条件立即保存状态。)
12、二叉搜索树的第K个节点: 解题思路:中序遍历
13、二叉树的下一个节点: 解题思路:两条路径,(1)若此节点的右子树存在,则递推返回右子树的最左节点。(2)若此节点的下一个节点是是根节点,若根节点的左节点==此节点,则返回根节点,否则继续向上递推根节点。
14、序列化二叉树: 解题思路:序列化:若空==‘#’然后中序遍历 反序列化:建立一个标志位用来索引序列列表。若非空,赋值root,递归root.left 和 root.right(其实序列化就是二叉树的前序遍历,反序列化就是前序重建二叉树)
17、二叉树的中序遍历、后序遍历:迭代法遍历二叉树,用颜色标记走过的节点位,然后用栈来实现遍历。
18、验证二叉搜索树:根据二叉搜索树的性质给出递归的出口条件,然后递归验证左右子树(注意递归左右子树传入的值,左子树的left=left,right=root.val,右子树的left=root.val,right=right)
19、恢复二叉搜索树:跟上面一样,多了一个交换节点值的步骤。
20、相同的树:因为是返回True或False所以return 递归。
21、将有序数组转为二叉搜索树:实际上就是中序遍历转二叉搜索树,因为不是唯一的,所以取中间元素作为根节点,左边就是左子树,右边就是右子树。
22、合法的二叉搜索树:递归:上面判断条件return进行递归 中序遍历:中序遍历二叉搜索树天然有序!!
25、节点与其祖先的最大差值:子函数寻找最大最小值
26、累加树:因为是二叉搜索树,所以中序遍历的反向就是从大到小排序(右中左),然后累加节点值更新下一节点值。
27、填充每个节点的下一个右节点指针:构造条件(左节点存在,则左节点的next指向右节点,next节点存在,则有节点的next指向next的左节点)+递归
28、填充每个节点的下一个右节点指针2:子函数寻找next节点的最左节点,主函数判断连接情况以后再递归(先右后左,因为有右边才有左边)
29、求根到叶子结点的数字和:简单条件加递归,注意找回递归根节点的值。
30、二叉搜索树的迭代器:迭代搜索树
31、二叉树的右视图:层序遍历
32、二叉搜索树中第k小元素:迭代法:利用栈保存树,中序遍历
33、二叉树的最近公共祖先:遍历查找,左没有就在右,右没有就在左,都有就在root
34、从先序遍历还原二叉树:用字典保存二叉树节点。遍历先序数组,保存字符和相应的深度,然后传入子函数建立树
35、字典树:用字典保存树儿子节点,字典嵌套。
字典树
class TrieNode():
def __init__(self,value,count):
self.value = value
self.count = count
self.children = {}
class Trie():
def __init__(self):
self.root = TrieNode(value = None,count = 0)
def build(self,words):
cur_node = self.root
for item in words:
if item not in cur_node.children:
child = TrieNode(value=item,count=0)
cur_node.children[item] = child
cur_node = child
else:
cur_node = cur_node.children[item]
cur_node.count +=1
def search(self,test_word):
cur_node = self.root
mark = True
for item in test_word:
if item not in cur_node.children:
mark = False
break
else:
cur_node = cur_node.children[item]
if cur_node.children:
mark = False
return mark
if __name__ == '__main__':
trie = Trie()
texts = ['what','rank','range','water','want','ranker','rant']
for text in texts:
trie.build(text)
markx = trie.search('what')
print(markx)
leetcode 24 二叉树和为某一值得路径(考察树的递归,注意最后的返回初始值)
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def __init__(self):
self.sumc = 0
self.a = []
self.b = []
# 返回二维列表,内部每个列表表示找到的路径
def FindPath(self, root, expectNumber):
# write code here
if not root:
return []
self.sumc += root.val
self.a.append(root.val)
if self.sumc == expectNumber and not root.left and not root.right:
self.b.append(self.a[:])
#若是有负数的话,则直接改为else
elif self.sumc < expectNumber:
self.FindPath(root.left,expectNumber)
self.FindPath(root.right,expectNumber)
self.sumc -=self.a[-1]
self.a.pop()
return self.b
94 二叉树的中序遍历(非递归版本)利用标定状态和栈来实现,有点像层序遍历
#
# @lc app=leetcode.cn id=94 lang=python3
#
# [94] 二叉树的中序遍历
#
# @lc code=start
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def inorderTraversal(self, root: TreeNode) -> List[int]:
WHITE, GRAY = 0, 1
res = []
stack = [(WHITE, root)]
while stack:
color, node = stack.pop()
if node is None: continue
if color == WHITE:
stack.append((WHITE, node.right))
stack.append((GRAY, node))
stack.append((WHITE, node.left))
else:
res.append(node.val)
return res
# @lc code=end
100 相同的数
# @before-stub-for-debug-begin
from python3problem100 import *
from typing import *
# @before-stub-for-debug-end
#
# @lc app=leetcode.cn id=100 lang=python3
#
# [100] 相同的树
#
# @lc code=start
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
'''
如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。
示例 1:
输入: 1 1
/ \ / \
2 3 2 3
[1,2,3], [1,2,3]
输出: true
示例 2:
输入: 1 1
/ \
2 2
[1,2], [1,null,2]
输出: false
'''
class Solution:
def isSameTree(self, p: TreeNode, q: TreeNode) -> bool:
if not p and not q:
return True
if not p or not q:
return False
if p.val != q.val:
return False
return self.isSameTree(p.left,q.left) and self.isSameTree(p.right,q.right)
# @lc code=end
102 二叉树的层序遍历和之字形遍历
#
# @lc app=leetcode.cn id=102 lang=python3
#
# [102] 二叉树的层序遍历
#
# @lc code=start
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def levelOrder(self, root: TreeNode) -> List[List[int]]:
if not root:
return []
queue = [root]
res = []
while queue:
cur = []
nextqueue = []
for i in queue:
cur.append(i.val)
if i.left:
nextqueue.append(i.left)
if i.right:
nextqueue.append(i.right)
queue = nextqueue
res.append(cur)
return res
#
# @lc app=leetcode.cn id=103 lang=python3
#
# [103] 二叉树的锯齿形层次遍历
#
# @lc code=start
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
# 层次遍历思想,栈实现逆序,精妙
def zigzagLevelOrder(self, root: TreeNode) -> List[List[int]]:
if not root:
return []
res = []
stack = [root]
flag = 0
while stack:
tmp = []
new_stack = []
while stack:
#精华,栈是逆序,所以就有了逆逆为正,正逆为逆。
cur = stack.pop()
tmp.append(cur.val)
if flag ==0:
if cur.left:
new_stack.append(cur.left)
if cur.right:
new_stack.append(cur.right)
else:
if cur.right:
new_stack.append(cur.right)
if cur.left:
new_stack.append(cur.left)
res.append(tmp)
stack = new_stack
flag = 1-flag
return res
# @lc code=end
104 二叉树的最大深度
class Solution:
def maxDepth(self, root: TreeNode) -> int:
if not root:
return 0
left = self.maxDepth(root.left)
right = self.maxDepth(root.right)
return max(left,right)+1
平衡二叉树(在求二叉树深度的基础上定义了一个全局变量self.res用来及时记录递归中不符合条件的状态)
class Solution:
def isBalanced(self, root: TreeNode) -> bool:
if not root:
return True
self.res = True
self.helper(root)
return self.res
def helper(self,root):
if not root:
return 0
left = self.helper(root.left)
right = self.helper(root.right)
if abs(left-right) >1:
self.res = False
return False
return max(left,right)+1
返回二叉树的最小深度(注意只有一条子树的情况)
class Solution:
def minDepth(self, root: TreeNode) -> int:
if not root:
return 0
left = self.minDepth(root.left)
right = self.minDepth(root.right)
#返回左节点或右节点为空的情况,也就是其中一个节点为0
if not left or not right:
return left+right+1
return min(left,right)+1
路径总和
class Solution:
def hasPathSum(self, root, sum):
"""
:type root: TreeNode
:type sum: int
:rtype: bool
"""
if not root:
return False
sum -= root.val
if not root.left and not root.right: # if reach a leaf
return sum == 0
return self.hasPathSum(root.left, sum) or self.hasPathSum(root.right, sum)
路径总和2,求出每条路径(类似于回溯)
class Solution:
def __init__(self):
self.res = 0
self.a = []
self.b = []
def pathSum(self, root: TreeNode, sum: int) -> List[List[int]]:
if not root:
return []
val = root.val
self.a.append(val)
self.res +=val
if sum==self.res and not root.left and not root.right:
self.b.append(self.a[:])
else:
self.pathSum(root.left,sum)
self.pathSum(root.right,sum)
self.res -= self.a[-1]
self.a.pop()
return self.b
二叉树展开为链表()
class Solution:
def flatten(self, root: TreeNode) -> None:
"""
Do not return anything, modify root in-place instead.
"""
if not root:
return None
if root.left:
#找到左子树的最右边节点
pre = root.left
while pre.right:
pre = pre.right
#将右节点挂在左子树的最右边节点上
pre.right = root.right
#再将整个左子树挂在根节点的右边
root.right = root.left
root.left = None
#上面就排好了右子树的一个节点,然后遍历右子树即可
self.flatten(root.right)
指向下一个节点的右侧节点(完全二叉树)(也就是每个子节点横向连接)
class Solution:
def connect(self, root: 'Node') -> 'Node':
if not root:
return None
if root.left:
root.left.next = root.right
if root.next:
root.right.next = root.next.left
self.connect(root.left)
self.connect(root.right)
return root
指向下一个节点的右侧节点(非完全二叉树)
class Solution:
def connect(self, root: 'Node') -> 'Node':
def helper(root):
while root.next:
if root.next.left:
return root.next.left
elif root.next.right:
return root.next.right
root = root.next
return None
if not root or (not root.left and not root.right):
return root
if root.left and root.right:
root.left.next = root.right
root.right.next = helper(root)
if root.left and not root.right:
root.left.next = helper(root)
if root.right and not root.left:
root.right.next = helper(root)
#先递归右子树再递归左子树,因为有右才有左!!!
self.connect(root.right)
self.connect(root.left)
return root
105 从前序与中序遍历构造二叉树
class Solution:
def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:
if len(preorder)==0:
return None
if len(preorder)==1:
return TreeNode(preorder[0])
left_pre = preorder[1:inorder.index(preorder[0])+1]
right_pre = preorder[inorder.index(preorder[0])+1:]
left_in = inorder[:inorder.index(preorder[0])]
right_in = inorder[inorder.index(preorder[0])+1:]
root = TreeNode(preorder[0])
root.left = self.buildTree(left_pre,left_in)
root.right = self.buildTree(right_pre,right_in)
return root
二叉树中的最大路径和(路径是指能连在一起的节点,但是不能相交)
class Solution:
def maxPathSum(self, root: TreeNode) -> int:
self.max_num = -20
self.find(root)
return self.max_num
def find(self,node):
if not node:
return 0
left = max(0,self.find(node.left))
right = max(0,self.find(node.right))
#这里由于node.val+left+right一定大于node.val+max(left,right)这种情况,所以省略。
self.max_num = max(self.max_num,node.val+left+right)
return node.val+max(left,right)#向上面的父节点递归
求根到叶子节点的数字和(回溯思想)
class Solution:
def __init__(self):
self.temp = 0
self.res = []
def sumNumbers(self, root: TreeNode) -> int:
if not root:
return 0
self.temp = self.temp*10 + root.val
self.sumNumbers(root.left)
self.sumNumbers(root.right)
if not root.left and not root.right:
self.res.append(self.temp)
self.temp = (self.temp - root.val)//10
return sum(self.res)
二叉搜索树迭代器
class BSTIterator:
def __init__(self, root: TreeNode):
self.stack = []
self.left_search(root)
def left_search(self,root):
while root:
self.stack.append(root)
root = root.left
def next(self) -> int:
"""
@return the next smallest number
"""
node = self.stack.pop()
if node.right:
self.left_search(node.right)
return node.val
def hasNext(self) -> bool:
"""
@return whether we have a next smallest number
"""
return len(self.stack)>0
翻转二叉树
class Solution:
def invertTree(self, root: TreeNode) -> TreeNode:
if not root:
return None
root.left,root.right = root.right,root.left
self.invertTree(root.left)
self.invertTree(root.right)
return root
二叉树的所有路径
class Solution:
def binaryTreePaths(self, root: TreeNode) -> List[str]:
paths = []
def helper(root,path):
if root:
path +=str(root.val)
if not root.left and not root.right:
paths.append(path)
else:
path +='->'
helper(root.left,path)
helper(root.right,path)
helper(root,'')
return paths
二叉树的序列化与反序列化
class Codec:
def serialize(self, root):
"""Encodes a tree to a single string.
:type root: TreeNode
:rtype: str
"""
def helper(root,path):
if not root:
path +='None,'
else:
path +=str(root.val) + ','
path = helper(root.left,path)
path = helper(root.right,path)
return path
return helper(root,'')
def deserialize(self, data):
"""Decodes your encoded data to tree.
:type data: str
:rtype: TreeNode
"""
def rhelper(l):
if l[0] == 'None':
l.pop(0)
return None
root = TreeNode(l[0])
l.pop(0)
root.left = rhelper(l)
root.right = rhelper(l)
return root
data_list = data.split(',')
root = rhelper(data_list)
return root
节点与其祖先的最大差值
class Solution:
def maxAncestorDiff(self, root: TreeNode) -> int:
if not root:
return None
self.res = 0
self.search(root,root.val,root.val)
return self.res
def search(self,root,maxroot,minroot):
if not root:
return
self.res = max(self.res,max(abs(maxroot-root.val),abs(minroot-root.val)))
if maxroot < root.val:
maxroot = root.val
if minroot > root.val:
minroot = root.val
self.search(root.left,maxroot,minroot)
self.search(root.right,maxroot,minroot)
return maxroot,minroot
二叉搜索树需要掌握的三个点:
1、二叉搜索树的中序遍历的序列是递增排序的序列。中序遍历的遍历次序:Left -> Node -> Right。
def inorder(root):
return inorder(root.left) + [root.val] + inorder(root.right) if root else []
2、Successor 代表的是中序遍历序列的下一个节点。即比当前节点大的最小节点,简称后继节点。 先取当前节点的右节点,然后一直取该节点的左节点,直到左节点为空,则最后指向的节点为后继节点。
def successor(root):
root = root.right
while root.left:
root = root.left
return root
3、Predecessor 代表的是中序遍历序列的前一个节点。即比当前节点小的最大节点,简称前驱节点。先取当前节点的左节点,然后取该节点的右节点,直到右节点为空,则最后指向的节点为前驱节点。
def predecessor(root):
root = root.left
while root.right:
root = root.right
return root
例题:450、删除二叉搜索树中的节点
给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。
一般来说,删除节点可分为两个步骤:
首先找到需要删除的节点;
如果找到了,删除它。
说明: 要求算法时间复杂度为 O(h),h 为树的高度。
示例:
root = [5,3,6,2,4,null,7]
key = 3
5
/
3 6
/ \
2 4 7
给定需要删除的节点值是 3,所以我们首先找到 3 这个节点,然后删除它。
一个正确的答案是 [5,4,6,2,null,null,7], 如下图所示。
5
/
4 6
/
2 7
另一个正确答案是 [5,2,6,null,4,null,7]。
5
/
2 6
\
4 7
class Solution:
def successor(self, root):
"""
One step right and then always left
"""
root = root.right
while root.left:
root = root.left
return root.val
def predecessor(self, root):
"""
One step left and then always right
"""
root = root.left
while root.right:
root = root.right
return root.val
def deleteNode(self, root: TreeNode, key: int) -> TreeNode:
if not root:
return None
# delete from the right subtree
if key > root.val:
root.right = self.deleteNode(root.right, key)
# delete from the left subtree
elif key < root.val:
root.left = self.deleteNode(root.left, key)
# delete the current node
else:
# the node is a leaf
if not (root.left or root.right):
root = None
# the node is not a leaf and has a right child
elif root.right:
root.val = self.successor(root)
root.right = self.deleteNode(root.right, root.val)
# the node is not a leaf, has no right child, and has a left child
else:
root.val = self.predecessor(root)
root.left = self.deleteNode(root.left, root.val)
return root
96 不同的二叉搜索树 (动态规划计算树)
#
# @lc app=leetcode.cn id=96 lang=python3
#
# [96] 不同的二叉搜索树
#
'''
给定一个整数 n,求以 1 ... n 为节点组成的二叉搜索树有多少种?
示例:
输入: 3
输出: 5
解释:
给定 n = 3, 一共有 5 种不同结构的二叉搜索树:
1 3 3 2 1
\ / / / \ \
3 2 1 1 3 2
/ / \ \
2 1 2 3
'''
# @lc code=start
class Solution:
def numTrees(self, n: int) -> int:
#dp[n]的含义是n个值的不同二叉搜索树的数量
dp = [0]*(n+1)
dp[0]=dp[1]=1
for j in range(2,n+1):
for i in range(1,j+1):
#i前面的全排列与i后面的全排列的积,叠加起来
dp[j] += dp[i-1]*dp[j-i]
return dp[-1]
# @lc code=end
95 不同的二叉搜索树(遍历并创建树)
# @before-stub-for-debug-begin
from python3problem95 import *
from typing import *
# @before-stub-for-debug-end
#
# @lc app=leetcode.cn id=95 lang=python3
#
# [95] 不同的二叉搜索树 II
#
# @lc code=start
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def generateTrees(self, n):
"""
:type n: int
:rtype: List[TreeNode]
"""
def generate_trees(start, end):
if start > end:
return [None,]
all_trees = []
for i in range(start, end + 1): # pick up a root
# all possible left subtrees if i is choosen to be a root
left_trees = generate_trees(start, i - 1)
# all possible right subtrees if i is choosen to be a root
right_trees = generate_trees(i + 1, end)
# connect left and right subtrees to the root i
for l in left_trees:
for r in right_trees:
current_tree = TreeNode(i)
current_tree.left = l
current_tree.right = r
all_trees.append(current_tree)
return all_trees
return generate_trees(1, n) if n else []
class Solution:
def generateTrees(self, n: int):
if n == 0:
return None
# 对dp进行初始化
dp = []
for i in range(0, n+1): # 初始化dp
dp.append([])
for j in range(0, n+1):
if i == j:
dp[i].append([TreeNode(i)])
elif i < j:
dp[i].append([])
else:
dp[i].append([None])
dp[0][0] = [None]
for i in range(n-1, 0, -1): # 自下向上进行循环
for j in range(i+1, n+1):
for r in range(i, j+1): # i-j每一个节点为顶点的情况
left = r+1 if r < j else r # 右边的值需要边界判断,不然会溢出数组
for x in dp[i][r-1]: # 左右子树排列组合
for y in dp[left][j]:
node = TreeNode(r)
node.left = x
node.right = y
if r == j:
node.right = None
dp[i][j].append(node) # dp[i][j]添加此次循环的值
return dp[1][n]
# @lc code=end
98 验证二叉搜索树
# @before-stub-for-debug-begin
from python3problem98 import *
from typing import *
# @before-stub-for-debug-end
#
# @lc app=leetcode.cn id=98 lang=python3
#
# [98] 验证二叉搜索树
#
# @lc code=start
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def isValidBST(self, root: TreeNode) -> bool:
def helper(root,left=float('-inf'),right=float('inf')):
if not root:
return True
if root.val<=left or root.val >=right:
return False
if not helper(root.left,left,root.val):
return False
if not helper(root.right,root.val,right):
return False
return True
return helper(root)
# @lc code=end
99 恢复二叉搜索树
#
# @lc app=leetcode.cn id=99 lang=python3
#
# [99] 恢复二叉搜索树
#
# @lc code=start
# 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
class Solution:
def recoverTree(self, root: TreeNode) -> None:
"""
Do not return anything, modify root in-place instead.
"""
def helper(root,low=float('-inf'),unper=float('inf')):
if not root:
return None
val = root.val
if root.right and val>=unper:
root,root.right = root.right,root
if root.left and val <=low:
root,root.left = root.left,root
helper(root.left,low,val)
helper(root.right,val,unper)
return root
return helper(root)
# @lc code=end
二叉搜索树中第K小的数(先找到最左节点,然后向上回溯找右节点,这样就是从小到大遍历了)
class Solution:
def kthSmallest(self, root: TreeNode, k: int) -> int:
self.stack = []
while True:
while root:
self.stack.append(root)
root = root.left
root = self.stack.pop()
k -=1
if not k:
return root.val
root = root.right
二叉搜索树的最近公共祖先(三种情况,左右子树各一个,那么返回根节点,都在左子树或右子树,那么递归的left或right就会有值,返回root即可)
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
# if p.val < root.val and q.val < root.val:
# return self.lowestCommonAncestor(root.left,p,q)
# elif p.val > root.val and q.val > root.val:
# return self.lowestCommonAncestor(root.right,p,q)
# else:
# return root
if not root or root == p or root == q: return root
left = self.lowestCommonAncestor(root.left, p, q)
right = self.lowestCommonAncestor(root.right, p, q)
if not left: return right
if not right: return left
return root
二叉搜索树与双向链表
class Solution:
def Convert(self, pRootOfTree):
if not pRootOfTree:
return pRootOfTree
if not pRootOfTree.left and not pRootOfTree.right:
return pRootOfTree
# 处理左子树
self.Convert(pRootOfTree.left)
left=pRootOfTree.left
# 连接根与左子树最大结点
if left:
while(left.right):
left=left.right
pRootOfTree.left,left.right=left,pRootOfTree
# 处理右子树
self.Convert(pRootOfTree.right)
right=pRootOfTree.right
# 连接根与右子树最小结点
if right:
while(right.left):
right=right.left
pRootOfTree.right,right.left=right,pRootOfTree
#找到双向链表的表头
while(pRootOfTree.left):
pRootOfTree=pRootOfTree.left
return pRootOfTree