0.总结
- 本问题尚未AC,原因是数字过大时,超出了时间限制。需要结合一个记忆化搜索过程。
1.题目
2.思想
思想:
是一个递归问题,考虑将不同的节点做根节点。然后将剩余的节点划分大小再作为左右子树。其可能性便是 num(left) * num(right)/2
左右子树的建树过程也如上述。
具体地说:
- 依次遍历所有节点,让其作为根节点,同时得到左右子树节点集合
- 遍历左右子树节点集合,依次选择其中一个作为根节点,重复上述步骤
3.代码
class Solution:
def numTrees(self, n: int) -> int:
res = 0
# 搞一个记忆化搜索,如果之前搜索过这个答案,直接返回输出
tuple2num={} # 存储每个tuple可能得到的建树数目
for i in range(n+1): # i 为root
left = [j for j in range(1,i)]
right = [j for j in range(i+1,n+1)]
# 得到左右节点集合
res += self.build_bin_search_tree(i,left,right,tuple2num)
return res/2
# 建二叉搜索树
def build_bin_search_tree(self,root,left,right,tuple2num):
# 边界返回条件
if len(left) == 0 and len(right) == 0: # 只有(放根节点)这一种选择
return 1
# 建左子树
left_num = 0 # 左子树的个数
len_left = len(left)
for left_root in range(len(left)):
left_left = [left[j] for j in range(0,left_root)] # 左子树的左子树
left_right = [left[j] for j in range(left_root+1,len_left)]
# if tuple(left_left) in tuple2num: # 如果这个已经搜索过,直接返回
left_num += self.build_bin_search_tree(left_root,left_left,left_right)
# 建右子树
right_num = 0
len_right = len(right)
for right_root in range(len_right):
right_left = [right[j] for j in range(0,right_root)]
right_right = [right[j] for j in range(right_root+1,len_right)]
right_num += self.build_bin_search_tree(right_root,right_left,right_right)
# 因为这里存在两种选择,所以最后要除以2
return max(left_num,1) * max(right_num,1)
s = Solution()
res = s.numTrees(1)
print(res/2)