不同的二叉搜索树(动态规划)
1. 题目描述
难度:中等
2. 题目分析
首先我们要知道二叉搜索树的特点:
- 左子树肯定小于其根节点
- 右子树肯定大于其根节点
- 第一个根节点的值总是大于左边的所有的节点的值
- 第一个根节点的值总是小于于右边的所有的节点的值
现在我们来看看怎么用动态规划来解决这个问题:
- 动态规划
动态规划的解决思路是从小问题开始,然后寻找动态转移方程,进而求解,我们来看看怎么得到动态转移方程的,以输入 n = 4 为例,节点的值分别是 nums = [1, 2, 3, 4]:- 当根节点的值为1时
这时左子树没有节点,右子树的节点有三个是 right = [2, 3, 4], 此时右子树的组合数与n=3时的组合数是等价的。 也就是说, right = [2, 3, 4] 与 [1, 2, 3]二者是等价的。所以,当根节点的值为1时,dp[root=1] = dp[n=3] - 当根节点的值为2时
这时左子树left = [1],右子树的节是 right = [3, 4], 此时左子树的组合数与n=1时的组合数是等价的,右子树的组合数与n=2时的组合数是等价的。 所以,当根节点的值为2时,dp[root=2] = dp[n=1] x dp[n=2] - 当根节点的值为3时
这时左子树left = [1, 2],右子树的节是 right = [4], 此时左子树的组合数与n=2时的组合数是等价的,右子树的组合数与n=1时的组合数是等价的。 所以,当根节点的值为3时,dp[root=3] = dp[n=2] x dp[n=1] - 当根节点的值为4时
这时左子树left = [1, 2, 3],右子树的节是 right = [], 此时左子树的组合数与n=3时的组合数是等价的。 所以,当根节点的值为2时,dp[root=2] = dp[n=3]
综上所述,我们就能得到前i个节点的组合数:
- 当根节点的值为1时
3. C语言实现
代码如下:
// 动态规划
int numTrees(int n){
if(n == 0) return 0;
int res;
int* dp = (int *)malloc(sizeof(int)*(n+1));
dp[0] = 1;
for(int i = 1; i < n+1; i++) dp[i] = 0;
for(int i = 1; i < n+1; i++){
for(int j = 0; j < i; j++)
dp[i] += dp[j]*dp[i-j-1];
}
res = dp[n];
free(dp);
return res;
}
运行结果为:
4. Python实现
代码如下:
class Solution:
def numTrees(self, n: int) -> int:
if not n:
return 0
dp = []
for i in range(n+1):
dp.append(0)
dp[0] = 1
for i in range(1, n+1):
for j in range(i):
dp[i] += dp[j]*dp[i-j-1]
return dp[n]
运行结果为: