二叉搜索树相关题目总结(二) 力扣 Python

本文介绍了两种不同的方法来解决与构造二叉搜索树相关的编程问题。第一种是通过递归和动态规划的回溯法,第二种利用了lru_cache进行优化。此外,还展示了动态规划的解决方案。文章提供了详细的代码实现,并解析了解题思路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前文 二叉搜索树相关题目总结(一) 中,主要是涉及二叉搜索树中的一些操作。

这篇文章是列举两道与构造 BST 有关的题目。

96. 不同的二叉搜索树

解题思路:

给定一个 n, 问从 1 到 n 能组成互不相同的 BST 有几种?

简单来看,就是穷举所有可能的树,然后算一下结果。

第一种方法,递归 DFS, 也是回溯的一种体现。

加入了名为 cache 的数组,也就是 dp 数组用于消除子问题重叠。

class Solution:
    
    def numTrees(self, n: int) -> int:
        cache = [-1] * (n + 1) # 初始化数组长度
        return self.countTrees(n, cache)

    def countTrees(self,n, cache):
    	#两个 base case
        if n == 0: 
            return 1
        if n == 1:
            return 1
		
		# -1 是数组初始化的值,只要不是 -1 就是已经存在的子问题,直接返回
        if cache[n] != -1: 
            return cache[n]
		#记录总的个数
        res = 0
        for i in range(n):
        	#分别列举可能构成的左右子树个数
            LeftTrees = self.countTrees(i, cache)
            RightTrees = self.countTrees(n - i - 1, cache)
			#以 i 为节点的树,其能构成不同的 BST 数目为 左右子树的乘机
            res += LeftTrees * RightTrees
        #从下往上记录节点组成树的个数
        cache[n] = res
        return res

解法二:

其实和解法一一致,只不过引入了 lru_cache 包,可以理解为一个隐式 cache 装饰器,用于自动缓存子问题。

代码相对于简洁。

class Solution:
    def numTrees(self, n: int) -> int:
        return self.countTrees(n)
    
    @lru_cache
    def countTrees(self, n: int) -> int:
        if n == 0:
            return 1

        if n == 1:
            return 1
 
        res = 0
        for i in range(n):
            left = self.countTrees(i)
            right = self.countTrees(n - i - 1)
            res += left * right

        return res

解法三:

动态规划,动态规划不明白可以看一下官方解释的图。

在这里插入图片描述
动态规划是一种从底向上的 DFS。

dp 数组用于记录重复子问题。

class Solution:
	def numTrees(self, n: int) -> int:
		#初始化 dp 数组
		dp = [0] * (n + 1)
    	dp[0], dp[1] = 1, 1

    	for i in range(2, n + 1):
       		for j in range(i):
        		#动态转移方程,穷举子问题
            	dp[i] += dp[j] * dp[i - j - 1]
        
     	return dp[n]

95. 不同的二叉搜索树 II

解题思路:
与 一思路一致,但这次要具体列出可能的子树,直接使用 DFS 然后记录每次可能的子树。

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def generateTrees(self, n: int) -> List[TreeNode]:

        if n == 0:
            return []

        return self.helper(1, n)

    def helper(self, start, end):

        if start > end:
            return[None]

        #记录所有可能的二叉搜索树
        res = []

        #对每一个数值穷举
        for curRoot in range(start , end + 1):

            #递归生成可能的左右子树
            leftSubtrees = self.helper(start, curRoot - 1)
            rightSubtrees = self.helper(curRoot + 1, end)

            for leftTree in leftSubtrees:
                for rightTree in rightSubtrees:

                    #合并每一个可能的组合
                    root = TreeNode(curRoot)
                    root.left = leftTree
                    root.right = rightTree
                    #添加组合
                    res.append(root)
                    
        return res
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Not_Today.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值