本文正在参加「Java主题月 - Java 刷题打卡」,详情查看<活动链接>
【Java 刷题打卡 】刷题比玩游戏好多了,成就感越来越强,每天坚持刷几道题,每天锻炼30分钟,等8块腹肌,等大厂offer.
那就干吧! 这个专栏都是刷的题目都是关于动态规划的,我会由浅入深、循序渐进,刷题就是这样需要连续不断的记忆--艾宾浩斯记忆法2121112。动态规划的内容不多,但是都是每个程序员必备的
什么题可以选择动态规划来做?
1.计数
有多少种方式走到右下角
有多少种方法选出k个数是的和是sum
2.求最大值最小值
从左上角走到右下角路径的最大数字和
最长上升子序列长度
3.求存在性
取石子游戏,先手是否必胜
能不能选出k个数使得和是sum
leecode 96. 不同的二叉搜索树
给定一个整数 n,求以 1 ... n 为节点组成的二叉搜索树有多少种? 示例:
输入: 3
输出: 5
解释:
给定 n = 3, 一共有 5 种不同结构的二叉搜索树:
-- 首先要知道二叉搜索树是根节点大于左节点小于右节点。
动态规划四步走~~~ ❤️❤️❤️❤️
2.1. 动态规划组成部分1:确定状态
简单的说,解动态规划的时候需要开一个数组,数组的每个元素f[i]或者f[i][j]代表什么,类似数学题中x, y, z代表什么
最后一步
给定一个有序序列 1 到n,为了构建出一棵二叉搜索树,我们可以遍历每个数字 ii,将该数字作为树根,将 1 到 (i-1)序列作为左子树,将 (i+1) 到n 序列作为右子树。接着我们可以按照同样的方式递归构建左子树和右子树。
在上述构建的过程中,由于根的值不同,因此我们能保证每棵二叉搜索树是唯一的。
子问题
由此可见,原问题可以分解成规模较小的两个子问题,且子问题的解可以复用。因此,我们可以想到使用动态规划来求解本题。
2.2. 动态规划组成部分2:转移方程
假设 n 个节点存在二叉排序树的个数是 G (n),令 f(i) 为以 i 为根的二叉搜索树的个数,则
G(n) = f(1) + f(2) + f(3) + f(4) + ... + f(n)
当 i 为根节点时,其左子树节点个数为 i-1 个,右子树节点为 n-i,则 f(i) = G(i-1)*G(n-i)
想一想这里为什么是笛卡尔积呢? \color{red}{想一想这里为什么是笛卡尔积呢?~}想一想这里为什么是笛卡尔积呢?
简单的将第二个公式带入第一个公式可以得到 (卡特兰数) 公式 G(n) = G(0)G(n-1)+G(1)(n-2)+...+G(n-1)*G(0)
2.3. 动态规划组成部分3:初始条件和边界情况
当序列长度为 1(只有根)或为 0(空树)时,只有一种情况,即 G(0)=1,G(1)=1
2.4. 动态规划组成部分4:计算顺序
自顶向下
参考代码
JAVA版
public int numTrees(int n) {
int[] dp = new int[n+1];
dp[0] = 1;
dp[1] = 1;
for(int i = 2; i < n + 1; i++)
for(int j = 1; j < i + 1; j++)
dp[i] += dp[j-1] * dp[i-j];
return dp[n];
}
真心感谢帅逼靓女们能看到这里,如果这个文章写得还不错,觉得有点东西的话
求点赞👍 求关注❤️ 求分享👥 对8块腹肌的我来说真的 非常有用!!!
如果本篇博客有任何错误,请批评指教,不胜感激 !❤️❤️❤️❤️