不同的二叉树搜索Ⅱ(动态规划)
1. 题目描述
难度:中等
2. 题目分析
这道题目是LeetCode96题.不同的二叉树搜索的进阶版,动态规划的思路还是不变的,但是难度提升就在于96题要求我们只需要输出组合的数目,而95题需要我们将所有的树的组合输出。
- 动态规划
根据96题,我们得到的动态转移方程为:
其实这一题动态转移方程式没有变,我们只需要更改dp的定义即可,在96题中,我们的dp[i]是存放前i个整数的有可能的组合数目,这一题我们dp[i]是存放的是一个列表,列表存放的是所有可能的二叉搜索树的根节点。这里有几个问题需要注意:
- 在前i个整数范围内,当根节点为1时
此时以1为根节点的数的左子树肯定为None - 在前i个整数范围内,当根节点为 i 时
此时以i为根节点的右子树肯定为None - 在前i个整数范围内,当根节点在1~i之间时
以 i = 6 为例,nums = [1, 2, 3, 4, 5, 6], 当以3为跟根节点是,左子树的可能组合与dp[2]移植,但是虽然右子树的组合数与dp[3]一致,但是dp[3]里是[1, 2, 3]构成的组合,并不是[4, 5, 6],所以我们还需要添加一个偏置,来使得dp[3]里面的树,变为[4, 5, 6]组合的树。
3. Python实现
代码如下:
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
# 返回修正偏差之后的树
def TreeNodeBias(n: TreeNode,bias: int) -> TreeNode:
if n is None:
return None
else:
nbias = TreeNode(n.val + bias)
nbias.left = TreeNodeBias(n.left, bias)
nbias.right = TreeNodeBias(n.right, bias)
return nbias
# 动态规划
class Solution:
def generateTrees(self, n: int) -> List[TreeNode]:
if(n == 0):
return []
"""
存放树的根节点
dp[i]表示前i个整数所生成的二叉搜索树的根节点
"""
dp = []
# 初始化dp列表
for _ in range(n+1):
dp.append([])
dp[0].append(TreeNode(None))
dp[1].append(TreeNode(1))
"""
i: 表示前i个整数, i <= n
j: 表示前i个整数的第j个数当做根节点
"""
for i in range(2, n+1):
for j in range(1, i+1):
left_num = j-1 # dp[left_num]为左子树的组合数
right_num = i-j # dp[right_num]为右子树的组合数
# 对左右子树的可能的情况进行组合
for left in range(len(dp[left_num])):
for right in range(len(dp[right_num])):
temp = TreeNode(j) # 根节点为j
if left_num == 0: # 如果j为1,那么左子树肯定是None
temp.left = None
else: # 否则,依次添加左子树
temp.left = dp[left_num][left]
if j != i: # 如果j == i,那么右子树肯定为None,因为是右子树,所以不用考虑添加None
temp.right = TreeNodeBias(dp[right_num][right], i-right_num)
dp[i].append(temp)
return dp[n]
运行结果为: