Leetcode 96:不同的二叉搜索树(超详细的解法!!!)

给定一个整数 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 2in)的情况,此时我们定义函数 f ( n ) f(n) f(n),返回以 n n n为输入的二叉树个数。我们知道根的左边有 i − 1 i-1 i1个数,而根的右边有 n − i n-i ni个数。那么左边二叉树的个数自然就是 f ( i − 1 ) f(i-1) f(i1),而右边二叉树的个数自然就是 f ( n − i ) f(n-i) f(ni)。那么此时以 i i i为根的二叉树有多少个呢?自然就是 f ( i − 1 ) ∗ f ( n − i ) f(i-1)*f(n-i) f(i1)f(ni)。此时我们还要一种情况没有考虑,就是 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(i1)f(ni)

我们的代码也可以非常容易的得到了

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

如有问题,希望大家指出!!!

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值