Leetcode第96题

题目

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

示例 1:

输入:n = 3 输出:5

示例 2:

输入:n = 1 输出:1

提示:

1 <= n <= 19

解题思路

这个题目主要的难度在公式推导上,我们可以用动态规划的思路来求解。

  • 令 \( G(N) \) 表示 n 互不相同的整数组成的二叉搜索树的数量。
  • \( F(i, N) \) 表示由 i 作为根节点,N 个互补相同的整数组成的二叉搜索树的数量
  • 可得, \( G(N) \) 是由每个 i 作为根节点的互不相同的二叉搜索树的数量的总和,此公式记做公式(1)
$$G(N) = \sum_{i=1}^{N} F(i, N) \tag{1}$$

接着,我们需要再推导出 \( F(i, N) \) 和 \( G(N) \) 的关系,就可以得到我们的递推公式了。

要想求 i 作为根节点,N 个互补相同的整数组成的二叉搜索树的数量,我们可以先求出左右两个子树的数量,左右两个子树相乘,即是总的数量。

例如,对于 1-7 组成, 3 作为根节点的二叉搜索树,左子树是 1-2 组成的二叉搜索树,右子树是 4-7 组成的二叉搜索树。

$$F(3, 7) = G([1-2]) * G([4-7])$$

又由于 5-7 和 1-3 都是三个节点,它们组成的二叉搜索树虽然值不同,但是树的数量是相同的。可得

$$F(4, 7) = G(3) * G(3)$$

进一步推广,我们可以得到公式(2)

$$F(i, N) = G(i-1) * G(N-i) \tag{2}$$

结合公式1和公式2, 我们可以得到递推公式

$$G(N) = \sum_{i=1}^{N} G(i-1) * G(N-1)$$

递推出口,也非常容易得到,树是0个或1个节点的时候,它的数量都是 1, 即

$$G(0) = 1 \\ G(1) = 1$$

题目要求的 由 n 个节点组成且节点值从 1 到 n 互不相同的二叉搜索树的数量 即是 \( G(N) \)

代码及复杂度

有了递推公式和递推出口之后,代码编写起来就非常容易了

func numTrees(n int) int {
	G := make([]int, n+1)
	G[0] = 1
	G[1] = 1
	for N := 2; N <= n; N++ {
		for i := 1; i <= N; i++ {
			G[N] += G[i-1] * G[N-i]
		}
	}

	return G[n]
}

上述代码的复杂度也非常容易分析

  • N 表示输入的整数
  • 时间复杂度 是看循环执行的次数,这是一个等差数列,所以时间复杂度是 \( O(N^2) \)
  • 空间复杂度 是看 G 数组的长度, 空间复杂度是 \( O(N) \)
2023年11月03日 / 08:45