考虑所有可以使用前N个自然数创建的高度≤H的二叉搜索树。找到这些二叉搜索树的根的总和。
例如,对于N = 3,H = 3:有2棵树,其中1作为根,1棵树,2作为根,2棵树,3作为根。
因此,Sum = 2 *(1)+ 1 *(2)+ 2 *(3)= 10
我试图通过以某种方式编写与f(n-1,h-1)和f(n-1,h)相关的函数f(n,h)来解决这个问题,但是无法找到解决方案。
注意:所有数字[1,N]必须存在于树中,高度应为≤H
答案 0 :(得分:1)
好吧,让我们从基础开始。
可以使用以下算法非常容易地计算使用前N个自然数可以创建的BST数量。
natural_number compute_no_of_BST(N)
{
if(N<=1)
return 1;
else
{
left=0,right=0,sum=0;
for(root = 1 to N)
{
left = compute_no_of_BST(root-1);
right = compute_no_of_BST(N-root);
sum = sum + (left*right);
}
return sum;
}
}
<强>解释强>:
理解这个算法的关键是:
无论不同的密钥是什么,BST的数量仅取决于不同密钥的数量
所以,这就是我们在递归中使用的。对于左子树,不同值的数量是root-1,对于右子树,不同值的数量是N-root。同样我们给每个键有机会成为root使用for循环。
现在,让我们处理高度H的约束。我假设高度是从根到叶子路径的边数。这也可以通过专注于上述算法来处理,技巧是:
我们不会调用高度&gt;的递归函数调用。 H和为此我们必须跟踪从根遍历的边数,最初为0。
所以这种情况会缩小到新函数调用的样子。
natural_number compute_no_of_BST(N,H,0);
每次我们进行递归调用时,我们都会增加第三个变量以指示边缘遍历。
我们还将使用额外的数据结构,这是一个长度为N的数组
arr[i] = number of BST with root i+1.
这是
的算法natural_number compute_no_of_BST(N,H,l)
{
if(N<=1)
return 1;
else
{
left=0,right=0,sum=0;
for(root = 1 to N)
{
if(l+1<=H)
{
left = compute_no_of_BST(root-1,H,l+1);
right = compute_no_of_BST(N-root,H,l+1);
if(l==0)
arr[root-1] = (left*right);
sum = sum + (left*right);
}
}
return sum;
}
}
现在总和可以很容易地计算为
arr[0]*1 + arr[1]*2 + ..... arr[N-1]*N.
答案 1 :(得分:1)
这里只是上述递归算法的DP转换。
int bottom_up_specific_height(int n,int h){
int i,j,l;
for(l=0;l<=h;l++){
dp[0][l]=1;
dp[1][l]=1;
}
int s=0;
for(i=2;i<=n;i++){
for(j=1;j<=i;j++){
for(l=h;l>=0;l--){
if(l==h)
dp[i][l]=0;
else
dp[i][l]+=(dp[j-1][l+1]*dp[i-j][l+1]);
if(l==0 && i==n)
s+=(j)*(dp[j-1][l+1]*dp[i-j][l+1]);
}
}
}
return s;
}
这里复杂度降低到O(h * n ^ 2)。 是否有可能进一步优化!!