赞
踩
问题:给你一个整数 n
,求恰由 n
个节点组成且节点值从 1
到 n
互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。
思路:动态规划最重要的就是找状态转移方程,这也是最难的,dp之所以比回溯快,是因为dp问题大多存在很多重复的子问题,感觉dp问题的重点是先将大问题划分为一个个重叠小问题,然后由底向上一步步解决,中途利用辅助数组记录每个子问题的值,这样使得每个子问题只需要计算一次就行,大大节省了时间。感觉将大问题拆解为一个个小问题之后,可以先从最小的问题慢慢向上推,然后列出状态转移方程。这样基本上就问题不大了。
这道题求n个节点可以组成多少种二叉搜索树。先从1个节点开始,一个节点肯定只能组成1种;然后n=2
,不难发现,答案是2,当n=3
时,我们也可以在纸上画出来,答案是5
,这样好像没有发现什么。我们换种想法:
当n=3
时,我们可以分别以1,2,3
分别为根节点构造二叉搜索树。
以1
根节点时,左子树没有节点,右子树有两个节点。而两个节点又可以构成两种不同的二叉搜索树,所以以1
为根节点时,可以构造1*2
种不同的二叉搜索树。
以2
为根节点时,左子树又一个节点,右子树有一个节点,我们可以得出以2
为节点时,可以构造1*1
种不同的二叉搜索树
以3
根节点时,左子树有两个节点,右子树没有节点。而两个节点又可以构成两种不同的二叉搜索树,所以以3
为根节点时,可以构造2*1
种不同的二叉搜索树。
所以n=3
时,可以构造2 + 1 + 2 = 5
中不同的二叉搜索树
以此类推,可以得到定义一个这样的函数searchNum(n)
,用来求n个节点可以构造的不同二叉搜索树的种数。
函数代码如下:
private int searchNum(int n){
int count = 0;
for(int i = 1; i <= n; i++ ){
count += searchNum(n - i) * searchNum(i - 1);
}
return count;
}
然后发现求解的过程中,存在好多重复计算,于是使用备忘录memo
优化,对于重叠子问题,只需要计算一次。最终代码如下:
class Solution { public int numTrees(int n) { int[] memo = new int[n + 1]; memo[0] = 1; memo[1] = 1; return searchNum(n, memo); } private int searchNum(int n, int[] memo){ if (memo[n] != 0) return memo[n]; int count = 0; for(int i = 1; i <= n; i++ ){ count += searchNum(n - i, memo) * searchNum(i - 1, memo); } memo[n] = count; return count; } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。