题目
给定一个整数 n,求以 1 ... n 为节点组成的二叉搜索树有多少种?
示例:
输入: 3 输出: 5
动态规划
public class Main {
public static void main(String[] args) {
Main main = new Main();
main.numTrees(4);
}
public int numTrees(int n) {
int [] dpTable = new int[n];
for (int i = 0; i < n; i ++) {
if (i == 0) {
dpTable[i] = 1;
}
if (i == 1) {
dpTable[i] = 2;
}
if (i >= 2) {
for (int j = 0; j <= i; j ++) {
// 当j为二叉树的root时
// j - 0 代表j左边的二叉树节点
// i - j 代表j右边的二叉树节点
int jLeft = 0;
if (j > 0) {
jLeft = dpTable[j - 1];
}
int jRight = 0;
if (j < i) {
jRight = dpTable[i - j - 1];
}
if (jLeft == 0 || jRight == 0) {
dpTable[i] = dpTable[i] + jLeft + jRight;
} else {
dpTable[i] = dpTable[i] + jLeft * jRight;
}
}
}
}
return dpTable[n - 1];
}
}
基本思路
-
首先明确搜索二叉树(注意不是完全二叉树)的定义, 即一棵二叉树中, 左节点的值 < 根节点的值 < 右节点的值.
-
输入为1...n, 是按顺序有规律的
-
然后发现当1到n中每个值如果分别作为总二叉树的根的时候, 例如当n = 4, 3为root, 那么1, 2 一定在3的左边, 4在3的右边. 即通过轮换不同的数字作为root, 可以分成两个子二叉树, 即两个子问题, 因此可以用动态规划来解决
-
也就是dp[i]代表当n为i的时候, 一共有多少种构成, 那么当i作为root节点, i之间的数字全部作为左子数, 那么左子数有多少种可能呢, 那就将左边子树从头遍历一遍, 每个节点作为左子树的root, 然后看当前root的左右一共有几种可能(已经计算过的)
-
采用dptable来记录子问题的答案
-
需要注意在计算某个root左右两边的节点数量和索引关系, 不要被绕晕了