题意:

image.png

解题思路:

  1. 思路1:
  2. 动态规划
  3. 假设n个节点存在
  4. G(n)的从1n可以形成二叉排序树个数
  5. f(i)为以i为根的二叉搜索树的个数
  6. 即有:G(n) = f(1) + f(2) + f(3) + f(4) + ... + f(n)
  7. 1. n为根节点,当i为根节点时,
  8. 2. 其左子树节点个数为[1,2,3,...,i-1],
  9. 3. 右子树节点个数为[i+1,i+2,...n],所以当i为根节点时,其左子树节点个数为i-1个,右子树节点为n-i,即f(i) = G(i-1)*G(n-i),
  10. 上面两式可得:G(n) = G(0)*G(n-1)+G(1)*(n-2)+...+G(n-1)*G(0)
  11. N cnt 组合
  12. 1 1 [1] => 1
  13. 2 2 [12] [21] => 2
  14. 3 5 1 2 3 => 5
  15. 针对i = 3
  16. 当选择1为根节点时:dp[1-1] * dp[3-1] => dp[0] * dp[2] :左边没有节点,右边有2个节点,可以组成:[123],[132]
  17. 当选择2为根节点时:dp[2-1] * dp[3-2] => dp[1] * dp[1] :左边一个节点,右边一个节点,可以组成:[中左右]:[213]
  18. 当选择3为根节点时:dp[3-1] * dp[3-3] => dp[2] * dp[0] :左边2个节点,右边没有节点,可以组成:[3,2,1][3,1,2]
  19. 所以当选择3时:dp[0] * dp[2] + dp[1] * dp[1] + dp[2] * dp[0] = 5
  20. 得出递推公式:d[i] = d[j-1] * d[$i-j];
  21. j = 1~i;=>j1遍历到i,最后返回dp[n]
  22. 思路2
  23. 对于每一个根i他都是由左边子树(1, 2, ..., i - 1)和右边子树(i + 1, i + 2, ..., n)组成的。
  24. 因此他的个数肯定是两个子树情况的积。而且,这种根一共有n个,再将这些加起来就可以了。

PHP代码实现:

  1. class Solution {
  2. /**
  3. * @param Integer $n
  4. * @return Integer
  5. */
  6. function numTrees($n) {
  7. //return $this->numTrees1($n);
  8. if ($n <= 1) return 1;
  9. $dp[0] = 1;
  10. $dp[1] = 1;
  11. for ($i = 2; $i <= $n; $i++) {
  12. for ($j = 1; $j <= $i; $j++) {
  13. //左子树:$dp[$j - 1]
  14. //右子树:$dp[$i - $j]
  15. $dp[$i] += $dp[$j - 1] * $dp[$i - $j];
  16. }
  17. }
  18. return $dp[$n];
  19. }
  20. function numTrees1($n) {
  21. if ($n <= 1) return 1;
  22. $res = 0;
  23. for ($i = 0; $i < $n; $i++) {
  24. $res += $this->numTrees1($i) * $this->numTrees1($n - $i - 1);
  25. }
  26. return $res;
  27. }
  28. }

GO代码实现:

  1. func numTrees(n int) int {
  2. G := make([]int, n + 1)
  3. G[0], G[1] = 1, 1
  4. for i := 2; i <= n; i++ {
  5. for j := 1; j <= i; j++ {
  6. G[i] += G[j-1] * G[i-j]
  7. }
  8. }
  9. return G[n]
  10. }