链接:https://leetcode-cn.com/problems/unique-binary-search-trees/
给定一个整数 n,求以 1 ... n 为节点组成的二叉搜索树有多少种?
示例:
输入: 3
输出: 5
解释:给定 n = 3, 一共有 5 种不同结构的二叉搜索树:
1 3 3 2 1
\ / / / \ \
3 2 1 1 3 2
/ / \ \
2 1 2 3
根据题意,我们需要寻找从 1 到 n 为节点的二叉搜索树的个数,所以我们先回忆下二叉搜索树的定义。
二叉查找树(Binary Search Tree),又称二叉搜索树、二叉排序树 ,它或者是一棵空树,或者是具有下列性质的二叉树:
当我们了解了二叉搜索树的定义后,我们就知道该以什么样的规则来构建一颗二叉搜索树。给定一个整数 n,可以根据数字的序列构建一棵二叉搜索树。首选,我们从 1 到 n,依次遍历每个数字 i,将 i 作为根节点,1~(i-1) 序列作为左子树,(i+1)~ n 序列作为右子树,之后对于左子树和右子树,我们可以根据同样的方法进行构建,这样递归的概念就从中诞生了。因为依次遍历的根节点各不相同,这样就保证了每棵二叉搜索树都是唯一的。
上面提到了递归,但是大家都知道递归很耗时,所以当我们可以使用动态规划的思想将问题分解成规模较小的子问题后,可以存储并复用子问题的解,而不是递归的调用这些子问题,接下来我们就看看如何用动态规划进行求解吧。
定义数组元素的含义
找出数组之间的递推表达式
找出初始值
虽然我们很容易知道 G[2] 的值,这里我们还是带入递推表达式的公式理解一下,这里我们用 dp 表示 G,dp[2] = f(1)+f(2)= dp[0] * dp[1] (1为根的情况) + dp[1] * dp[0] (2为根的情况)。
时间复杂度:O(n^2)
空间复杂度:O(n)
Python:
class Solution:
def numTrees(self, n: int) -> int:
dp=[0]*(n+1)
dp[0]=1
dp[1]=1
for i in range(2,n+1):
for j in range(1,i+1):
dp[i]+=dp[j-1]*dp[i-j]
return dp
Go:
func numTrees(n int) int {
dp:=make([]int,n+1)
dp[0],dp[1]=1,1
for i:=2;i<=n;i++{
for j:=1;j<=i;j++{
dp[i]+=dp[j-1]*dp[i-j]
}
}
return dp[n]
}
如果想要优化时间复杂度和空间复杂度,可以通过卡特兰数。卡特兰数有一个递推关系,但是对于卡特兰数的证明我也不会,大家可以自行 Google 或者百度搜索了解一下吧。
递推关系如下:
时间复杂度:O(n)
空间复杂度:O(1)
Python:
class Solution:
def numTrees(self, n: int) -> int:
C=1
for i in range(n):
C=2*(2*i+1)*C/(i+2)
return int(C)
Go:
func numTrees(n int) int {
C:=1
for i:=0;i<n;i++{
C=2*(2*i+1)*C/(i+2)
}
return C
}
如果觉得文章不错,希望大家可以扫描上方名片关注我的微信公众号噢,点赞、收藏、在看、分享就再好不过了。如果有任何建议和问题,可以在下方给我留言,我会及时回复的,同时会不定期更新更多的文章,祝我们终将自由。