给定一个整数 n,求以 1 ... n 为节点组成的二叉搜索树有多少种?
目录
所谓动态规划,所涉及的问题是要求的问题会与前面的子问题相关联,并由前面的子问题推导而来,这一点如果学过数学归纳法就会觉得十分眼熟。
作为这道题而言,所谓二叉搜索树,其必须满足的条件就是,左子树的所有成员一定都小于根节点,右子树的所有成员一定都大于根节点。
举例分析
当n为3时,那么就有三种情况。
- 数字1作为根节点
- 数字2作为根节点
- 数字3作为根节点
当数字1作为根节点时,有几种情况呢,是不是1的左子树的所有情况乘上1的右子树的所有情况呢。
好,根1的左边不可能存在数,故情况只能为一种(即没有子树的这一种情况)
根1的右子树还有
2,3
,2,3
有几种情况呢,让我们想想,2,3
的情况其实就是n为2时的所有子树情况。
那么好,我们再举一个例子
当n为4的时候。
总共有4种情况,分别是根节点为
1,2,3,4
的时候,根节点为1
我们就不分析了。我们直接来分析根节点为2
的情况:当根节点为
2
时他的左子树里只能有数字
1
一个数字,故左子树的情况数量为当n=1时的搜索树数量;他的右子树里有数字
3,4
两个数字,故右子树的情况数量为当n=2时的搜索树数量。
这样,递推关系就确定了。
vector<int> dp(n+1);
for(int i=1;i<n+1;i++)//这里是遍历顺序,只有前面的都推过才能推到后面。
{
for(int j=1;j<i+1;j++)//每一个的不同情况,即每一个的1~i种情况
{
do[i]+=dp[i-1]*dp[i-j];//情况和
}
}
dp[n]为n的二叉搜索树数量,下标为n。
那么怎么去推到n呢,当然是从前向后遍历。
这个应该比较好理解,比如n=10,那么就是根为1~10的所有情况的和,但是我们要知道dp[10],就必须先知道dp[1]~dp[9]。
最后就能推到dp[10]了
整体代码
#include <iostream>
#include <vector>
using namespace std;
class solution
{
public:
int nercahshu(int n)
{
vector<int> dp(n+1);
dp[0]=1;
//dp[1]=1;
//dp[2]=2;
/*for(int k=1;k<i;k++)
{
dp[i]+=dp[k-1]*dp[i-k];
}
*/
for(int i=1;i<n+1;i++)
{
for(int j=1;j<i+1;j++)
{
if(j==1)
{
dp[i]+=dp[i-1];
}
else
{
dp[i]+=dp[j-1]*dp[i-j];
}
}
}
return dp[n];
}
};
int main() {
std::cout << "Hello World!\n";
solution so;
cout<<so.nercahshu(5);
}