题目分析:
给定一个整数 n,生成所有由 1 … n 为节点所组成的二叉搜索树。
示例:
输入: 3
输出:
[
[1,null,3,2],
[3,2,null,1],
[3,1,null,null,2],
[2,1,3],
[1,null,2,null,3]
]
解释:
以上的输出对应以下 5 种不同结构的二叉搜索树:
解题思路:
这一题可以用递归或递归+动态规划解,我们先说递归帮助理解,这一题的动态规划实际上时递归的一个优化。
这一题使用递归解涉及递归思想与二叉树搜索树,如果没有一定知识储备会很难想。这个题我看了好几个博客(其实都差不多),最后还是通过不断调试明白了原理。我们先通过递归的思想使用【LeetCode】96. Unique Binary Search Trees 的方法构造某个节点的所有左右子树,例如:
- 1进入程序作为第一个节点
- 它的左节点一定是None(没有比1小的)
- 开始添加1的右节点(可选2,3)
- 2进入程序
- 2的左节点为None(1用过了)
- 添加2的右节点(只有3可选)
- 3进入程序
- 3的左节点为None(1,2用过了)
- 3的右节点为None(没有比3大的)
- 构成了下图左侧的一棵搜索树
- 返回到第三步,这次选择3
- 3进入程序
- 3的左节点为2(1用过了)
- 2进入程序
- 2的左节点为None(1用过了)
- 添加2的右节点None(3用过了)
- 返回到第13步
- 3的右节点为None(没有比3大的)
- 构成了下图右侧的一棵搜索树(带左图的1,不再标写)
- 返回到第一步,以2作为程序第一个节点
- … …
代码实现,递归的话我们要标记现在够成树的起点与终点(因为要知道哪些节点可选)def dfs(self, start, end):
,从某一点i开始
能构成左子树的可选项时从start到i - 1(这个范围内的值小于i),同理能构成左子树的可选项时从i + 1到end,代码实现就是:
for i in range(start, end + 1):
Left_Tree = self.dfs(start, i - 1)
Right_Tree = self.dfs(i + 1, end)
有了左右子树我们就可以开始以i为根节点构成一棵树,代码如下:
for l_t in Left_Tree:
for r_t in Right_Tree:
root = TreeNode(i)
root.left = l_t
root.right = r_t
这就是递归的基本思路了,动态规划就是建立一个字典存储每次start到end的子树形状,保存结果为后续相同的小子树直接返回结果,先把递归搞懂,递归+动态规划直接看代码即可。
提交代码1:(递归,Runtime: 64 ms, faster than 69.94% )
class Solution:
def dfs(self, start, end):
res = []
if start > end: return [None]
for i in range(start, end + 1):
Left_Tree = self.dfs(start, i - 1)
Right_Tree = self.dfs(i + 1, end)
for l_t in Left_Tree:
for r_t in Right_Tree:
root = TreeNode(i)
root.left = l_t
root.right = r_t
res.append(root)
return res
def generateTrees(self, n):
if n == 0: return []
return self.dfs(1, n)
提交代码2:(递归 + 动态规划,Runtime: 56 ms, faster than 96.26% )
class Solution:
def generateTrees(self, n: 'int') -> 'List[TreeNode]':
if not n: return []
if n == 1: return [TreeNode(1)]
return self.dfs(1, n, {})
def dfs(self, start, end, cache):
if start > end: return [None]
if start == end: return [TreeNode(start)]
if (start, end) in cache: return cache[(start, end)]
trees = []
for i in range(start, end + 1):
for l_t in self.dfs(start, i - 1, cache):
for r_t in self.dfs(i + 1, end, cache):
root = TreeNode(i)
root.left = l_t
root.right = r_t
trees.append(root)
cache[(start, end)] = trees
return trees
参考博客1,参考博客2,以及LeetCode 95. Unique Binary Search Trees II提交代码中的第一个