给定一个整数 n,求以 1 … n 为节点组成的二叉搜索树有多少种?
示例:
输入: 3
输出: 5
解释:
给定 n = 3, 一共有 5 种不同结构的二叉搜索树:
1 3 3 2 1
\ / / / \ \
3 2 1 1 3 2
/ / \ \
2 1 2 3
解题思路
这个问题通过递归很容易就可以求解,我们知道如果给定整数是1
的话,那么我们的结果只可能是1
。如果给定的整数大于1
的话我们就要思考了。我们考虑根为
i
i
i(
2
≤
i
≤
n
2 \le i \le n
2≤i≤n)的情况,此时我们定义函数
f
(
n
)
f(n)
f(n),返回以
n
n
n为输入的二叉树个数。我们知道根的左边有
i
−
1
i-1
i−1个数,而根的右边有
n
−
i
n-i
n−i个数。那么左边二叉树的个数自然就是
f
(
i
−
1
)
f(i-1)
f(i−1),而右边二叉树的个数自然就是
f
(
n
−
i
)
f(n-i)
f(n−i)。那么此时以
i
i
i为根的二叉树有多少个呢?自然就是
f
(
i
−
1
)
∗
f
(
n
−
i
)
f(i-1)*f(n-i)
f(i−1)∗f(n−i)。此时我们还要一种情况没有考虑,就是
n
=
0
n=0
n=0,此时应该返回1
。
- f ( 0 ) = 1 f(0)=1 f(0)=1
- f ( 1 ) = 1 f(1)=1 f(1)=1
- f ( n ) = ∑ i = 1 n f ( i − 1 ) ∗ f ( n − i ) f(n)=\sum_{i=1}^{n}f(i-1)*f(n-i) f(n)=∑i=1nf(i−1)∗f(n−i)
我们的代码也可以非常容易的得到了
class Solution:
def numTrees(self, n):
"""
:type n: int
:rtype: int
"""
if n == 0 or n == 1:
return 1
res = 0
for j in range(1, n + 1):
res += self.numTrees(j-1) * self.numTrees(n-j)
return res
我们可以像之前解决这类问题的思路一样通过记忆化搜索的方式优化这个问题。
class Solution:
def numTrees(self, n):
"""
:type n: int
:rtype: int
"""
mem = [0]*(n+1)
mem[0], mem[1] = 1, 1
return self._numTrees(n, mem)
def _numTrees(self, n, mem):
if n == 0 or n == 1:
return 1
if mem[n] != 0:
return mem[n]
for i in range(1, n + 1):
mem[n] += self._numTrees(i-1, mem)*self._numTrees(n-i, mem)
return mem[n]
所以我们就不难写出动态规划的形式。
class Solution:
def numTrees(self, n):
"""
:type n: int
:rtype: int
"""
mem = [0]*(n+1)
mem[0], mem[1] = 1, 1
for i in range(2, n + 1):
for j in range(1, i + 1):
mem[i] += mem[j - 1]*mem[i - j]
return mem[-1]
我将该问题的其他语言版本添加到了我的GitHub Leetcode
如有问题,希望大家指出!!!