说明
给定二叉树的节点个数来计算能够构成多少种不同的二叉树。
操作
采用的是递归的思想来解决这类问题。
1、因为采用递归的思想,我们的结束条件就是当节点个数为0.此时节点个数为0的情况,这时候构成的树的情况为空树,即二叉树的个数是1.
2、因为是二叉树,我们只需要分为两边来计算。即满足这样的条件,从根节点下来,能够成左边的情况的个数乘以右边的个数的情况想乘,就得到此时这种情况的个数。例如:总共有3个节点,左边分配2个(能构成的情况为2),右边分配1个节点(能构成的情况为1),即本次分配的情况总数为2*1=2
3、实际上节点数为1的时候,构成的情况也是1,和0是一样的,所以递归的条件,就是当节点数为0就结束。所以每次的结果都会递归到0。
代码实现:
'''
计算二叉树的个数
'''
def count(n):
# root : 1
# left : k [0,n-1]
# right : n - 1 - k
if n == 0:
return 1
sum = 0
for k in range(n):
sum += count(k) * count(n-1-k)
return sum
用一张图来表示调用栈的变化以及程序的执行过程。我们以n=3为例,其他的(n更大)的情况都是一样的计算。
上图,详细解释了每一步的执行过程。上述调用栈的过程遵从左到右、从上到下的过程。执行过程遵从,从右到做、从下到上的顺序。
总结
在上述的代码中,有一个很大的缺点,在调用栈中就体现得很明确,当我们第一步执行count(0)和count(2)后,发现后面还会用到这些,会被重复的在调用栈中执行,在时间和空间上都是很大的浪费。
解决方法,我们可以建立一个缓存机制,使得每次执行过的count()被保存在缓存中,这样的话,当我们下次执行到ciunt()时,如果已经在缓存中,就直接从缓存中取(时间复杂度为O(1)),如果不存在我们才会递归。
其代码如下:
'''
添加缓存的方式来实现时间复杂度下降
'''
def count_tree(n):
# root : 1
# left : k [0,n-1]
# right : n - 1 - k
sum = count_tree.cache.get(n,0)
if sum:
return sum
for k in range(n):
sum += count_tree(k) * count_tree(n-1-k)
return sum
count_tree.cache = {0:1}