题目:
小红定义一个二叉树为“好二叉树”,当且仅当该二叉树所有节点的孩子数量为偶数(0或者2)。
小红想知道,n个节点组成的好二叉树,共有多少种不同的形态?答案请对10^9+7取模。
1 ≤ n ≤ 3000
思路:
首先先排除偶数个节点,这种情况下不可能是好二叉树
当只有一个节点(1种) 有三个节点(一种) 有5个节点(2种)
用sum[n]表示有n个节点时二叉树的形态
再往下列就会发现,第i个节点的形态是由根节点的左节点和右节点的组合数决定的,即sum[i] = sum[left] * sum[i - 1 - left]
参考:https://blog.youkuaiyun.com/weixin_44867329/article/details/137086289
代码:
class Solution {
public:
int cntOfTrees(int n) {
// 如果是偶数,不是好二叉树
if(n % 2 == 0) return 0;
const int mod = 1000000007;
// 用数组存放好二叉树数量
vector<long> sum(3001);
// 初始化
sum[1] = 1;
sum[3] = 1;
// 循环:每个奇数的好二叉树数量,这里的步长是2
for(int i = 5; i <= n; i += 2){
int num = i - 1; // 除去根节点,当前可分配节点数量
// 循环:对左子树节点数量遍历,注意左右节点对称不是同一种形态,所以左节点要从1取到num-1
for(int j = 1; j < num; j += 2){
// 这里的取模要取两次,否则结果是错的
sum[i] += (sum[j] * sum[num - j]) % mod;
sum[i] %= mod;
}
}
return sum[n];
}
};
总结:
1. 注意取模要在两个地方都取
2. 左右对称属于两种不同的形态(如左1右3和左3右1是不同的),因此要注意左子树节点的遍历边界