Skip to content

Commit

Permalink
Update 0096. 不同的二叉搜索树.md
Browse files Browse the repository at this point in the history
  • Loading branch information
itcharge committed May 31, 2023
1 parent 3f5f0ff commit ded47d1
Showing 1 changed file with 72 additions and 11 deletions.
83 changes: 72 additions & 11 deletions Solutions/0096. 不同的二叉搜索树.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,81 @@

## 题目大意

给定一个整数 `n`,求以 `1``n` 为节点构成的「二叉搜索树」有多少种?
**描述**:给定一个整数 $n$。

**要求**:求以 $1$ 到 $n$ 为节点构成的「二叉搜索树」有多少种?

**说明**

- $1 \le n \le 19$。

**示例**

- 示例 1:

![](https://assets.leetcode.com/uploads/2021/01/18/uniquebstn3.jpg)

```Python
输入:n = 3
输出:5
```

- 示例 2:

```Python
输入:n = 1
输出:1
```

## 解题思路

动态规划求解。
### 思路 1:动态规划

一棵搜索二叉树的左、右子树,要么也是搜索二叉树,要么就是空树。

如果定义 $f[i]$ 表示以 $i$ 为根的二叉搜索树个数,定义 $g(i)$ 表示 $i$ 个节点可以构成的二叉搜索树个数,则有:

- $g(i) = f(1) + f(2) + f(3) + … + f(i)$。

`1``n` 的每个节点都可以用来做根节点。每一个根节点 `i` 都是由左子树 `(1, 2, ..., i - 1)` 和右子树 `(i + 1, i + 2, ..., n)` 构成的。则二叉搜索树的个数肯定是两个子树个数的乘积。而根节点有 `n` 个,最终将这些个数累加起来即可。
其中当 $i$ 为根节点时,则用 $(1, 2, , i - 1)$ 共 $i - 1$ 个节点去递归构建左子搜索二叉树,用 $(i + 1, i + 2, , n)$ 共 $n - i$ 个节点去递归构建右子搜索树。则有:

定义 `f[i]` 为以 `i` 为根节点的二叉搜索树个数,`dp[i]``i` 个节点构成的二叉搜索树个数。则:
- $f(i) = g(i - 1) \times g(n - i)$。

`dp[i] = f(1) + f(2) + ... + f(i)`
综合上面两个式子 $\begin{cases} g(i) = f(1) + f(2) + f(3) + … + f(i) \cr f(i) = g(i - 1) \times g(n - i) \end{cases}$ 可得出:

`i` 为根节点时,其左子树节点个数为 `i - 1`,右节点个数为 `n - i`。则:
- $g(n) = g(0) \times g(n - 1) + g(1) \times g(n - 2) + … + g(n - 1) \times g(0)$。

`f(i) = dp[i - 1] * dp[n - i]`
将 $n$ 换为 $i$,可变为:

则总和上述公式可定义状态 `dp[i]` 表示: `i` 个节点构成的二叉搜索树个数
- $g(i) = g(0) \times g(i - 1) + g(1) \times g(i - 2) + … + g(i - 1) \times g(0)$

状态转移方程为 `dp[i] = dp[0] * dp[i - 1] + dp[1] * dp[i - 2] + ... + dp[i - 1] * dp[0]`
再转换一下,可变为:

即:`dp[i] += dp[j - 1] * dp[i - j]`,其中 `1 ≤ j ≤ i`
- $g(i) = \sum_{1 \le j \le i} \lbrace g(j - 1) \times g(i - j) \rbrace$

## 代码
则我们可以通过动态规划的方法,递推求解 $g(i)$,并求解出 $g(n)$。具体步骤如下:

###### 1. 划分阶段

按照根节点的编号进行阶段划分。

###### 2. 定义状态

定义状态 $dp[i]$ 表示为: $i$ 个节点可以构成的二叉搜索树个数。

###### 3. 状态转移方程

$dp[i] = \sum_{1 \le j \le i} \lbrace dp[j - 1] \times dp[i - j] \rbrace$

###### 4. 初始条件

- $0$ 个节点可以构成的二叉搜索树个数为 $1$(空树),即 $dp[0] = 1$。

###### 5. 最终结果

根据我们之前定义的状态,$dp[i]$ 表示为: $i$ 个节点可以构成的二叉搜索树个数。。 所以最终结果为 $dp[n]$。

### 思路 1:代码

```Python
class Solution:
Expand All @@ -40,3 +92,12 @@ class Solution:
return dp[n]
```

### 思路 1:复杂度分析

- **时间复杂度**:$O(n^2)$。
- **空间复杂度**:$O(n)$。

## 参考资料

- 【题解】[画解算法:96. 不同的二叉搜索树 - 不同的二叉搜索树](https://leetcode.cn/problems/unique-binary-search-trees/solution/hua-jie-suan-fa-96-bu-tong-de-er-cha-sou-suo-shu-b/)

0 comments on commit ded47d1

Please sign in to comment.