动态规划之不同的二叉搜索树

54 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第13天,点击查看活动详情

动态规划(Dynamic Programming)是一种分阶段求解决策问题的数学思想,它通过把原问题分解为简单的子问题来解决复杂问题。

不同的二叉搜索树

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

示例 1:

输入:n = 3 输出:5

示例 2:

输入:n = 1 输出:1

二叉搜索树

它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉搜索树。

思路:

把第i个节点看作是根节点, 那么所产生的所有可能性为 左子树的所有可能性 * 右子树所有可能性 当根节点为i的时候, 左边为 n - 1 个节点所形成的子树,右边为 n - i 个节点所形成的子树, 假设dp[i]表示为有多少个节点所形成的子树,k[i] 表示第i个节点为根节点的可能性。 k[i] = dp[i - 1] * dp[n - i] dp[i] = k[1] + k[2]......k[i]

依题可知:

  • 当 n = 0 时,没有数字,只能形成一种满足题意的二叉搜索树 :空树。
  • 当 n = 1 时,只有一个数字,只能形成一种满足题意的二叉搜索树 :单个节点。

代码如下:

fun numTrees(n: Int): Int {
    val dp = IntArray(n + 1)
    dp[0] = 1
    for (i in 1..n) {
        var count = 0
        for (j in 1..i) {
            count += dp[j - 1] * dp[i - j]
        }
        dp[i] = count
    }
    return dp[n]
}
  • 时间复杂度 : O(n^2),需要遍历两次。
  • 空间复杂度 : O(n)。我们需要 O(n) 的空间存储dp数组。