题目描述
记忆化搜索
对于每个节点而言都可以在区间1到n中取一个数作为根节点,比如这里取i,则左子树能在根节点1 – i - 1中取值作为根节点,右子树能在i + 1 – n中取值作为根节点。最后当前节点能取的可能就是左右子树能取可能情况的乘积。对于子树节点我们可以以同样的方式递归地去求。由于这样会有很多重复的计算,所以我们用一个map来记录已经计算过的结果,避免重复计算,这就是记忆化搜索。
unordered_map<string,int> mp;
int numTrees(int n) {
return dfs(1, n);
}
int dfs(int s, int e)
{
string key = to_string(s)+"#"+to_string(e);
if(mp.find(key) != mp.end()) return mp[key];
if(s > e) return 1;
int rs = 0;
for(int i = s; i <= e; i++)
rs += dfs(s,i-1) * dfs(i+1,e);
mp.insert({key, rs});
return rs;
}
卡特兰数列
卡特兰数列百科
假设n个节点存在二叉排序树的个数是G(n),令f(i)为以i为根的二叉搜索树的个数,则
G(n) = f(1) + f(2) + f(3) + f(4) + … + f(n)
当i为根节点时,其左子树节点个数为i-1个,右子树节点为n-i,则
f(i) = G(i-1)*G(n-i)
综合两个公式可以得到 卡特兰数 公式
G(n) = G(0)G(n-1) + G(1)(n-2) +…+ G(n-1)*G(0)
int numTrees(int n)
{
vector<int> dp(n+1);
dp[0] = 1;
dp[1] = 1;
for(int i = 2; i < n + 1; i++)
for(int j = 1; j < i + 1; j++)
dp[i] += dp[j-1] * dp[i-j];
return dp[n];
}