分析问题
分析题意,二叉搜索树的不同的原因在于数组中所有的元素均可以成为祖先节点,因此
- 第一步: 遍历数组,使得每一个元素都可以成为祖先节点。
- 第二步,确定好祖先节点之后,数组中的剩余n-1个数就会被分成两拨,左子树由小于祖先节点的数组成,有节点由大于祖先节点的数组成
当祖先节点值为 i i i 时,左子树最大的数为 i − 1 i -1 i−1, 于是左子树的元素个数可以从0增加到 i − 1 i - 1 i−1 。
例如: 当n=3是 num = [1, 2, 3]
此时根节点有三种情况:
- 1为根节点时,1的左子树是0个,右子树是2,3(两个)。所以1是根节点的种类树是: res[0] * res[2]
- 2为根节点时,2的左子树是1(1个),右子树是3(1个)。所以2是根节点的种类树是: res[1] * res[1]
- 3为根节点时,3的左子树是1,2(2个),右子树是0个。所以3是根节点的种类树是: res[2] * res[0]
所以 res[3] = res[0]*res[2] + res[1]*res[1] + res[2]*res[0]
确认状态
d
p
[
0
]
=
1
dp[0] = 1
dp[0]=1: 没有节点只有一种情况,空树
d
p
[
1
]
=
d
p
[
0
]
∗
d
p
[
0
]
=
1
dp[1] = dp[0] * dp[0] = 1
dp[1]=dp[0]∗dp[0]=1:只有一个节点也是一种情况
假设n=3时:
i i i | d p [ i ] dp[i] dp[i] | |||
---|---|---|---|---|
i = 1 i = 1 i=1 | d p [ 1 ] = d p [ 0 ] ∗ d p [ 0 ] dp[1] = dp[0] * dp[0] dp[1]=dp[0]∗dp[0] | 1 | ||
i = 2 i = 2 i=2 | d p [ 2 ] = d p [ 0 ] ∗ d p [ 1 ] dp[2] = dp[0] * dp[1] dp[2]=dp[0]∗dp[1] | d p [ 2 ] = d p [ 1 ] ∗ d p [ 0 ] dp[2] = dp[1] * dp[0] dp[2]=dp[1]∗dp[0] | 2 | |
i = 3 i = 3 i=3 | d p [ 3 ] = d p [ 0 ] ∗ d p [ 2 ] dp[3] = dp[0] * dp[2] dp[3]=dp[0]∗dp[2] | d p [ 3 ] = d p [ 1 ] ∗ d p [ 1 ] dp[3] = dp[1] * dp[1] dp[3]=dp[1]∗dp[1] | d p [ 3 ] = d p [ 2 ] ∗ d p [ 0 ] dp[3] = dp[2] * dp[0] dp[3]=dp[2]∗dp[0] | 5 |
问题公式化:
d p ( n ) = { 1 , n = 0 ∑ i = 1 n d p ( i − 1 ) d p ( n − i ) , if n ≥ 1 dp(n)= \begin{cases} 1, & \text {$n=0$ } \\ \sum_{i=1}^{n} dp(i-1)dp(n-i), & \text{if $n \geq 1$ } \end{cases} dp(n)={1,∑i=1ndp(i−1)dp(n−i),n=0 if n≥1
// 参考程序
class Solution:
def numTrees(self, n):
"""
:type n: int
:rtype: int
"""
if n == 0 or n == 1:
return 1
dp = [0] * (n+1)
dp[0] = 1 // 初始状态
for i in range(1, n+1):
for j in range(i):
dp[i] += dp[j] * dp[i-j-1]
return dp[n]