leetcode专题训练96 Unique Binary Search Trees

这篇博客详细介绍了LeetCode第96题的三种解法,包括利用上一题思路避免回溯以优化时间复杂度,使用动态规划求解,以及揭示问题与卡特兰数的联系。解法1通过建立查找表减少重复计算,解法2利用动态规划的递推公式解决,解法3介绍卡特兰数公式直接求解。
摘要由CSDN通过智能技术生成

解法1:
这道题和95题 Unique Binary Search Trees II很像,但是解题思路却相差很多。先用上一道题的思路按照递归写了一下,最后TLE超时了,后来想了一下超时原因,发现这道题由于只用输出个数,不用输出具体的树,所以右边界和左边界的差值相同的子树,数量都是相同的,所以就可以打个表,把已经算过的右边界和左边界的差值记录下来,下次再遇到相同的范围时,可以直接从表中获得结果,不用再回溯了。
需要注意在为表赋初始值时,一定要注意这个初始值能否真正到达。最开始我设置了result_list[1]=2,并没有考虑到n=1的情况,WA了一发,以后一定要注意。

class Solution:
    def numTrees(self, n: int) -> int:
        if n <= 0:
            return 0

        # 用于打表,索引是右边界和左边界的差值
        result_list = [0 for i in range(n)]
        result_list[0] = 1

        def recurse(begin: int, end: int) -> int:
            if begin >= end:
                return 1

            if result_list[end-begin] != 0:
                return result_list[end-begin]

            result = 0
            for i in range(begin, end+1):
                left = recurse(begin, i-1)
                right = recurse(i+1, end)
                result += left*right
            result_list[end-begin] = result
            return result

        return recurse(1, n)

解法2:
在解法1通过之后,看了一下题解,发现这道题可以用动态规划来解。因为一个树可以由左二叉搜索子树和右二叉搜索子树构成,而且相同节点个数的二叉搜索子树的个数相同。设dp[i]表示有i个节点数的二叉搜索树个数,而由于左子树和右子树的节点数都比i少,那么左右子树的二叉搜索树个数就已经算出来,可以直接用在dp[i]的计算上。以有3个节点的二叉搜索树为例:

dp[3]=dp[0]*dp[2]+dp[1]*dp[1]+dp[2]*dp[0]

所以动态规划方程为:
d p [ i ] = ∑ j = 0 i d p [ j ] ∗ d p [ i − j − 1 ] dp[i]=\sum^i_{j=0}{dp[j]*dp[i-j-1]} dp[i]=j=0idp[j]dp[ij1]
其中j是该搜索树左子树的节点个数。
需要注意dp[0]*dp[2]和dp[2]*dp[0]是对称的,值是一样的,所以可以将上式改为:

dp[3]=2*dp[0]*dp[2]+dp[1]*dp[1]

故,整体的代码如下:

class Solution:
    def numTrees(self, n: int) -> int:
        if n <= 0:
            return 0
        if n == 1:
            return 1

        dp = [0 for i in range(n+1)]
        dp[0] = 1
        dp[1] = 1
        for i in range(2, n+1):
            for j in range(i//2):
                dp[i] += 2*(dp[j]*dp[i-j-1])
            if i%2:
                dp[i] += dp[i//2]*dp[i//2]
        
        return dp[n]

解法3:
官方题解中说这个其实是卡特兰数,公式为:
在这里插入图片描述
有了公式之后,按照公式写代码就好了,没有什么难度,所以此处直接把题解拷贝在了下面,没有自己重新写。

class Solution(object):
    def numTrees(self, n):
        """
        :type n: int
        :rtype: int
        """
        C = 1
        for i in range(0, n):
            C = C * 2*(2*i+1)/(i+2)
        return int(C)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值