前中、中后可以确定唯一二叉树,前后不可以。因为没有中序遍历无法确定左右部分,也就是无法分割。
106.从中序与后序遍历序列构造二叉树
思路:
说到一层一层切割,就应该想到了递归
。
来看一下一共分几步:
第一步:如果数组大小为零的话,说明是空节点了。
第二步:如果不为空,那么取后序数组最后一个元素
作为节点元素。
第三步:找到后序数组最后一个元素在中序数组的位置,作为切割点
第四步:切割中序数组,切成中序左数组和中序右数组 (顺序别搞反了,一定是先切中序数组)
第五步:切割后序数组,切成后序左数组和后序右数组(中左和后左 中右和后右 长度是一样 所以可以根据切割的中序的长度来分)
第六步:递归处理左区间和右区间
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution(object):
def buildTree(self, inorder, postorder):
"""
:type inorder: List[int]
:type postorder: List[int]
:rtype: TreeNode
"""
# 第一步: 特殊情况讨论: 树为空. (递归终止条件)
if not postorder:
return None
# 第二步: 后序遍历的最后一个就是当前的中间节点.
root_val = postorder[-1]
root = TreeNode(root_val)
# 第三步: 找切割点.
separator_index = inorder.index(root_val)
# 第四步: 切割inorder数组. 得到inorder数组的左,右半边.
inorder_left = inorder[:separator_index]
inorder_right = inorder[separator_index + 1:]
# 第五步: 切割postorder数组. 得到postorder数组的左,右半边.
# ⭐️ 重点1: 中序数组大小一定跟后序数组大小是相同的.
postorder_left = postorder[:len(inorder_left)]
postorder_right = postorder[len(inorder_left):len(postorder) - 1]
#第六步 递归
root.left = self.buildTree(inorder_left, postorder_left)
root.right = self.buildTree(inorder_right, postorder_right)
return root
105.从前序与中序遍历序列构造二叉树
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution(object):
def buildTree(self, preorder, inorder):
"""
:type preorder: List[int]
:type inorder: List[int]
:rtype: TreeNode
"""
# 1树空 条件终止
if not preorder:
return None
# 2找前序第一个
root_val = preorder[0]
root = TreeNode(root_val)
# 3 在中序中找分割点
separator_index = inorder.index(root_val)
# 4分割中序
inorder_left = inorder[:separator_index]
inorder_right = inorder[separator_index + 1:]
# 5分割前序 长度于中序同
preorder_left = preorder[1:len(inorder_left) + 1]
preorder_right = preorder[len(inorder_left) + 1:]
# 6递归
root.left = self.buildTree(preorder_left, inorder_left)
root.right = self.buildTree(preorder_right,inorder_right)
return root
654最大二叉树
思路:前序 :因为先选出最大值构建根节点 不断分两部分 每次选出最大值作为新的根 —递归
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution(object):
def constructMaximumBinaryTree(self, nums):
"""
:type nums: List[int]
:rtype: TreeNode
"""
if not nums:
return None
# 找到最大值和下标值
maxvalue = max(nums)
index = nums.index(maxvalue)
root = TreeNode(maxvalue)
#分割数组
left = nums[:index]
right = nums[index + 1:]
root.left = self.constructMaximumBinaryTree(left)
root.right = self.constructMaximumBinaryTree(right)
return root
617.合并二叉树
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution(object):
def mergeTrees(self, root1, root2):
"""
:type root1: TreeNode
:type root2: TreeNode
:rtype: TreeNode
"""
# 递归终止条件
# 但凡有一个节点为空, 就立刻返回另外一个. 如果另外一个也为None就直接返回None.
if not root1:
return root2
if not root2:
return root1
# 单层逻辑 前序
root1.val += root2.val #中
root1.left = self.mergeTrees(root1.left, root2.left)# 左
root1.right = self.mergeTrees(root1.right, root2.right)# 右
# ⚠️ 注意: 本题我们重复使用了题目给出的节点而不是创建新节点. 节省时间, 空间. 直接在root1上修改
return root1
700.二叉搜索树中的搜索
思路:
二叉搜索树是一个有序树:
若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
它的左、右子树也分别为二叉搜索树
这就决定了,二叉搜索树,递归遍历和迭代遍历和普通二叉树都不一样。
因为搜索到目标节点了,就要立即return了,这样才是找到节点就返回(搜索某一条边),如果不加return,就是遍历整棵树了。
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution(object):
def searchBST(self, root, val):
"""
:type root: TreeNode
:type val: int
:rtype: TreeNode
"""
# 为什么要有返回值:
# 因为搜索到目标节点就要立即return,
# 这样才是找到节点就返回(搜索某一条边),如果不加return,就是遍历整棵树了。
# 递归结束条件
if not root or root.val == val:
return root
if root.val > val:
return self.searchBST(root.left, val)
if root.val < val:
return self.searchBST(root.right, val)
98.验证二叉搜索树
要知道中序遍历下,输出的二叉搜索树节点的数值是有序序列。
有了这个特性,验证二叉搜索树,就相当于变成了判断一个序列是不是递增的了。
# 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 isValidBST(self, root: Optional[TreeNode]) -> bool:
# 思路: 利用BST中序遍历的特性.
# 中序遍历输出的二叉搜索树节点的数值是有序序列
candidate = []
#打印中序的数组
def __traverse(root):
nonlocal candidate
if not root:
return
__traverse(root.left)
candidate.append(root.val)
__traverse(root.right)
def __issorted(nums):
for i in range(1,len(nums)):
if nums[i] <= nums[i - 1]:
return False
return True
__traverse(root)
res = __issorted(candidate)
return res
530.二叉搜索树的最小绝对差
注意是二叉搜索树,二叉搜索树可是有序的。
遇到在二叉搜索树上求什么最值啊,差值之类的,就把它想成在一个有序数组上求最值,求差值,这样就简单多了。
#递归
# 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 getMinimumDifference(self, root: TreeNode) -> int:
candicate = []
def __traversal(root):
nonlocal candicate
if not root:
return
__traversal(root.left)
candicate.append(root.val)
__traversal(root.right)
def __findmin(nums):
minval = nums[1] - nums[0]
for i in range(1,len(nums)):
if nums[i] - nums[i - 1] < minval:
minval = nums[i] - nums[i - 1]
return minval
__traversal(root)
res = __findmin(candicate)
return res
501.二叉搜索树中的众数
# 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 findMode(self, root: TreeNode) -> List[int]:
candicate = []
res = []
def __traversal(root):
nonlocal candicate
if not root:
return
__traversal(root.left)
candicate.append(root.val)
__traversal(root.right)
def __findmost(nums):
nonlocal res
dict = {}
for x in nums:
if x in dict:
dict[x] += 1
else:
dict[x] = 1
maxvalue = max(dict.values())
# 注意items是key value
for k,v in dict.items():
if v == maxvalue:
res.append(k)
return res
__traversal(root)
__findmost(candicate)
return res
遍历一遍二叉树
# 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 __init__(self):
self.pre = TreeNode()
self.count = 0
self.max_count = 0
self.result = []
def findMode(self, root: TreeNode) -> List[int]:
if not root: return None
self.search_BST(root)
return self.result
def search_BST(self, cur: TreeNode) -> None:
if not cur: return None
self.search_BST(cur.left) # 左
# 第一个节点 中
if not self.pre:
self.count = 1
# 与前一个节点数值相同
elif self.pre.val == cur.val:
self.count += 1
# 与前一个节点数值不相同
else:
self.count = 1
self.pre = cur
if self.count == self.max_count:
self.result.append(cur.val)
if self.count > self.max_count:
self.max_count = self.count
self.result = [cur.val] # 清空self.result,确保result之前的的元素都失效
self.search_BST(cur.right)# 右
236. 二叉树的最近公共祖先
如果递归函数有返回值,如何区分要搜索一条边,还是搜索整个树呢?
搜索一条边的写法:
if (递归函数(root->left)) return ;
if (递归函数(root->right)) return ;
搜索整个树写法:
left = 递归函数(root->left);
right = 递归函数(root->right);
left与right的逻辑处理;
在递归函数有返回值的情况下:如果要搜索一条边,递归函数返回值不为空的时候,立刻返回,如果搜索整个树,直接用一个变量left、right接住返回值,这个left、right后序还有逻辑处理的需要,也就是后序遍历中处理中间节点的逻辑(也是回溯)
https://programmercarl.com/0236.%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E6%9C%80%E8%BF%91%E5%85%AC%E5%85%B1%E7%A5%96%E5%85%88.html
没看懂 = =
"""二叉树的最近公共祖先 递归法"""
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
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 left and right:
return root
if left:
return left
return right
235. 二叉搜索树的最近公共祖先
在有序树里,如果判断一个节点的左子树里有p,右子树里有q呢?
其实只要从上到下遍历的时候,cur节点是数值在[p, q]区间中则说明该节点cur就是最近公共祖先了。
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
# 过大 应该在左子树找
if root.val > p.val and root.val > q.val:
return self.lowestCommonAncestor(root.left, p, q)
# 过小 应该在右子树找
if root.val < p.val and root.val < q.val:
return self.lowestCommonAncestor(root.right, p, q)
# 在区间内 返回root
else:
return root