二叉搜索树练习——不同的二叉搜索树、不同的二叉搜索树 II
二叉搜索树
二叉搜索树是一种特殊的二叉树,它的左子节点小于根节点,根节点小于右子节点。如果使用中序排列的话,得到的结果是一个升序排列。如图所示的二叉搜索树的中序排列为
[
1
,
2
,
4
,
5
,
8
,
9
,
10
]
\left[1,2,4,5,8,9,10\right]
[1,2,4,5,8,9,10]
Leetcode不同的二叉搜索树
问题描述:
给定一个整数n,求以1至n为节点组成的二叉搜索树有多少种?
示例:
输入: 3
输出: 5
思考:
首先给定一个数n,根据这个数生成一个升序列表,先考虑根节点root,每个数都可以成为根节点root,因此需要一个for循环来确定根节点root的值;
然后是根节点往下的左子树和右子树。这时将刚刚root节点左边的数作为左子树的根节点的候选数,右边的数作为右子树的根节点的候选数。
如图所示,左子树的根节点root有三种可能,右子树的根节点root有一种可能,这时从左子树的三种可能中依次选取数值作为根节点,由于此时右子树仅有一种可能,那么就不需要针对右子树进行向下传递了,并且要返回值1,表示仅有一种可能。
此时发现,有的左子树或右子树不存在,因此需要返回值1,表示当前节点的左子树或右子树仅有一种可能,即null。接下来继续向下传递。
将左右子树候选个数为1或0的情况,返回值1,表示此时已经只有确定的二叉搜索树了,不存在候选的情况。最后开始回溯,从最下面的结点开始,将他们的可能的左子树的个数乘上可能的右子树的个数,即为当前节点为根节点的二叉搜索树的可能的个数。
需要注意的是,直接使用递归算法,会出现超时的情况,这是因为数据集是一堆整数,假如第一个数是5,代表此时计算的二叉搜索树有五个节点;接下来的数是10,表示此时计算的二叉搜索树的节点个数是10,其中当递归过程中,出现子树可能的根节点个数为5时,会重新进行计算,而不是用之前一次计算中,节点数为5时的结果,这样造成了重复计算的情况,会大大延长计算时间。因此在进行递归的过程中,保存每次计算的结果,以便后续调用,减少计算时间。
具体代码如下
class Solution:
#定义一个字典,存储每次计算的结果
save_result = dict()
def numTrees(self, n: int) -> int:
#当出现之前已经计算过的情况,调用之前的结果
if n in self.save_result:
return self.save_result.get(n)
#当左子树或右子树的叶子节点个数为0或1时,终止递归,并返回1
if n <= 1:
return 1
result = 0
#递归过程
for root in range(1, n + 1):
result += self.numTrees(root - 1) * self.numTrees(n - root)
self.save_result[n] = result
return result
Leetcode不同的二叉搜索树 II
问题描述:
给定一个整数n,生成所有由1至n为节点所组成的 二叉搜索树 。
示例:
输入: 3
输出: [[1,null,3,2],[3,2,null,1],[3,1,null,null,2],[2,1,3],[1,null,2,null,3]]
思考:
首先还是要先考虑根节点root,用for循环来遍历一组数,让每个数都作为根节点。
然后将root两边的数进行划分,左侧作为左子树的节点,右侧作为右子树的节点,然后使用for循环嵌套结构,将当前遍历的左侧数组的数字作为当前根节点的左子树根节点,右侧数组的数字作为当前根节点的右子树根节点。
接下来对每组数都进行相同的操作,即依次选择根节点,作为左右子树的根节点,并划分数组。当最后数组中不存在数字时,即已经确定了一棵二叉搜索树时,停止遍历。
具体代码如下
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
class Solution:
def generateTrees(self, n: int) -> List[TreeNode]:
if n == 0: return []
def loop(number_list):
if len(number_list) == 0:
return [None]
result_tree = []
for root in range(len(number_list)):
for left_number in loop(number_list[: root]):
for right_number in loop(number_list[root + 1:]):
tree_node = TreeNode(number_list[root])
tree_node.left = left_number
tree_node.right = right_number
result_tree.append(tree_node)
return result_tree
return loop(list(range(1, n+1)))