「前端刷题」96. 不同的二叉搜索树

50 阅读2分钟

「这是我参与2022首次更文挑战的第4天,活动详情查看:2022首次更文挑战」。

题目

链接:leetcode-cn.com/problems/un…

给你一个整数 n ,求恰由 n 个节点组成且节点值从 1n 互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。

示例 1:

**输入:**n = 3 **输出:**5

示例 2:

**输入:**n = 1 **输出:**1

提示:

  • 1 <= n <= 19

思路

刚看到题目一开始想到的是排列组合问题,后来发现规律难寻就画出如下草图,然后花了一分钟搞定了。

1.对于整数n,互不相同的二叉搜索数量 = 所有以1到n为根节点的组合数量之和。
2.以i为根节点的组合数量 = 左子树节点组合数 * 右子树节点组合数。

假设我们要求当给定的整数n为5时的组合数。
1.我们要枚举以1,2,3,4,5为根节点的组合数量,将每一种情况的组合数相加就是最终结果。
2.假设此时要求以2为根节点的组合数量。根据二叉搜索树的定义,左子树上的节点数量为1(比2小的只有1),右子树上的节点数量是3(比2大的有3,4,5)。那么以2为根节点的组合数量 = 节点数量为1时的组合数 * 节点数量为3时的组合数。

那么怎么知道节点数量为i时的组合数呢,我们可以直接定义:当节点数量为i时,互不相同的二叉搜索树为dp[i]。
当根节点为2时,组合数 = dp[1] * dp[3];

所以状态转移方程就直接出来了 dp[i] = dp[左侧节点数量] * dp[右侧节点数量]

考虑最简单的情况:当n=0时,dp[0] = 1(无为而治,没有节点也是一种组合)

代码

function numTrees(n: number): number {
    const dp = new Array(n).fill(0);
    dp[0] = 1;
    
    for(let i = 1;i < dp.length;i++){
        for(let j = 0;j < i;j++){
            dp[i] += (dp[j] * dp[i - j - 1]);
        }
    }

    return dp[n];
};

思路

  • n个数的解是可以利用的
  • n + 1的解,就是循环 1 -- n+1,然后计算
var numTrees = function (n) {
  let map = [1, 1];
  for (let i = 2; i <= n; i++) {
    let num = 0;
    for (let a = 1; a <= i; a++) {
      num += map[a - 1] * map[i - a];
    }
    map[i] = num;
  }
  return map[n];
};