提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
累 想玩
一、题目
不同的二叉搜索树 II
给你一个整数 n ,请你生成并返回所有由 n 个节点组成且节点值从 1 到 n 互不相同的不同 二叉搜索树 。可以按 任意顺序 返回答案。
示例
示例 1:
输入:n = 3
输出:[[1,null,2,null,3],[1,null,3,2],[2,1,3],[3,1,null,null,2],[3,2,null,1]]
示例 2:
输入:n = 1
输出:[[1]]
提示
1 <= n <= 8
二、思路
这个解法的本质还是一种dfs,带有回溯的操作。
输出的结果是一个列表,其中是所有可能的二叉搜索树的根结点
首先,构造二叉搜索树就是一个递归的过程,将某个结点作为根结点,然后其前和其后的区间再构成另外的二叉搜索树;其次,对于一段区间,如果把所有的结点依次拿出来作为根结点,然后把其所有可能的左子树和右子树依次组合起来,就可以得到所有可能的二叉搜索树
在实现上,每次可以把树的根结点存储在列表中,在遍历中方便连接
三、代码
# 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 generateTrees(self, n: int) -> List[Optional[TreeNode]]:
if(n==0): #n=0时,返回空列表,没有符合要求的树
return []
def build_Trees(left,right): #在left和right区间内生成树,返回由这个区间的数字生成树的根结点的集合(列表)
all_trees=[] #返回的列表
if(left>right): #返回空,作为叶子结点的标志
return [None]
for i in range(left,right+1): #把区间内的每一个值依次用作根结点
left_trees=build_Trees(left,i-1) #生成其左子树
right_trees=build_Trees(i+1,right) #生成其右子树
for l in left_trees:
for r in right_trees: #组合所有左子树和右子树的选择
cur_tree=TreeNode(i) #生成根结点
cur_tree.left=l
cur_tree.right=r #分配左右子树
all_trees.append(cur_tree) #加入列表
return all_trees #返回列表
res=build_Trees(1,n) #调用函数
return res
四、题目
不同的二叉搜索树
给你一个整数 n ,求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。
示例
示例 1:
输入:n = 3
输出:5
示例 2:
输入:n = 1
输出:1
提示
1 <= n <= 19
通过次数301,135提交次数425,649
五、思路
这道题虽然跟上面的描述一样,但因为数据规模扩大了一倍,所以如果仍然用dfs,只是改成计数的话,就会超时。
因此选择用递推的方法(dp,动态规划):
这种方法可以成立的关键是,假设G(n)是长度为n的(连续)序列构成的二叉搜索树的个数 则 G(n)的值与具体数值无关,只与n有关;
因此,而G(n)的递推公式为,用i(1~n所有数依次)当根结点,然后G(i-1)*G(n-i)的和;
初始值:G(0)=1(当做叶子结点标志);G(1)=1;
六、代码
class Solution:
def numTrees(self, n: int) -> int:
#假设G(n)是长度为n的(连续)序列构成的二叉搜索树的个数 则 G(n)的值与具体数值无关,只与n有关
#而G(n)的递推公式为,用i(1~n所有数依次)当根结点,然后G(i-1)*G(n-i)的和
#初始值:G(0)=1(当做叶子结点标志);G(1)=1
G=[1 for x in range(20)]
for j in range(2,n+1):
temp=0
for i in range(1,j+1):
temp+=G[i-1]*G[j-i]
G[j]=temp
return G[n]