题目描述:
给你一个整数 n
,求恰由 n
个节点组成且节点值从 1
到 n
互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。
输入输出样例
输入
n = 3
输出
5
提示
1 <= n <= 19
思路:
这题我使用递归,由于是二叉搜索树,也就是对于任何一个树中的节点A,左边的节点都小于A的值,右边的节点都大于A的值。那么对于一个给定的n个数字,大小不一的序列,假设我们先按照从小到大的顺序将其排列好,数字下标为0,1,2……n-1
,将该序列组织成二叉搜索树,那么树根节点有n种情况,也就是0号数字作为树根,1号数字作为树根等等。
如果0号数字作为树根,那么树根的左孩子会是空,树根的右孩子看做一棵子树,这个子树一共有n-1个节点,因此0号节点作为树根(共有n个节点的二叉搜索树,其中左子节点为空)的情况数目就等于有n-1个节点的二叉搜索树的情况数目。
如果我们以1号节点作为树根,左孩子只能有0号节点,右孩子是一颗有n-2个节点的二叉搜索树,所以1号节点为树根(共有n个节点的二叉搜索树,左孩子是只有一个元素,右孩子是一颗n-2个节点的树)的情况数目就等于有n-2个节点的二叉搜索树的情况数目……
因此这就是递归,递归函数getNum(int n)
是求由n个不同数字组成的二叉搜索树的情况数目,终止情况是,当n为0或者n为1。n为1,情况数目为1,n为0,要注意情况数目也为1。
我们将建立一个表numTable,其中numTable[n]记录n个不同数字组成的二叉搜索树的情况数目,这是因为递归过程中可能多次调用同一个函数,查表能够更快的得到结果。该表初始都是0。
注意:
确定根节点后,我们会分别将左子树和右子树看做两颗二叉搜索树,得到左边的情况数目和右边的情况数目时,两者相乘才是总数目。
此外还要注意,n为0时,getNum(n)的值是1而不是0。
代码如下:
class Solution {
public:
int numTrees(int n) {
int numsTable[20] = {0}; // 作为表,记录一下
int res = getNum(n, numsTable);
for (int i = 0; i <= n; ++i)
cout<<numsTable[i]<<" ";
return res;
}
int getNum(int n, int* numsTable)
{
if (n == 1 || n == 0)
{
numsTable[n] = 1;
return 1;
}
// 还是要递归
int res = 0;
for (int i = 0; i < n; ++i)
{
// 左边放i个
if (numsTable[i] == 0)
numsTable[i] = getNum(i, numsTable);
// 右边放n-1-i个;
if (numsTable[n-1-i] == 0)
numsTable[n-1-i] = getNum(n-1-i, numsTable);
res += (numsTable[i] * numsTable[n-1-i]);
}
numsTable[n] = res;
return res;
}
};