一、前言
参考文献:代码随想录
今天的动态规划比较抽象,做好心理准备吧!
回忆一下动态规划五部曲:
1、创建并明确dp数组的含义;
2、初始化dp数组;
3、确定推导公式;
4、确定遍历顺序;
5、打印dp数组;
二、整数拆分
1、思路:
题解的思路我是真想不到,只能学习。。。
(1)首先还是确定dp数组:
vector<int> dp(n + 1);
数组长度为什么是n+1呢?因为数组是从0开始记录i大小的数的拆分乘积最大值;
(2)初始化dp数组:
dp[0] = 0;
dp[1] = 0;
dp[2] = 1;
比较好理解,只需要确定前三个即可,后面的最大值都可以通过后续步骤推出;
(3)递推公式:
dp[i] = max(max(dp[i - j] * j, (i - j) * j), dp[i]);
看起来可能比较抽象,首先是dp[i - j] * j 这个是拆分成dp[ i -j]的前提下(这里的pd[i]已经是最大值了),再乘以j与(i - j) * j进行比较,这里是拆成两个。然后就是挑选最大值了;
(4)遍历顺序:
for (int i = 3; i <= n; i++) {
// 这里的一个小细节是i/2,因为后面的数字都已经做过比较了
for (int j = 1; j <= i / 2; j++) {
// 4、推导公式
dp[i] = max(max(dp[i - j] * j, (i - j) * j), dp[i]);
}
}
有一个小细节,就是i/2这里是一个去重;
打印出来的数组,大概是这样;
2、整体代码如下:
class Solution {
public:
int integerBreak(int n) {
// 1、创建dp数组,dp[i]表示当前的拆分的最大乘积数
// i代表数字
vector<int> dp(n + 1); // 从0开始记录
// 2、初始化dp数组
dp[0] = 0;
dp[1] = 0;
dp[2] = 1;
// 3、遍历顺序
for (int i = 3; i <= n; i++) {
// 这里的一个小细节是i/2,因为后面的数字都已经做过比较了
for (int j = 1; j <= i / 2; j++) {
// 4、推导公式
dp[i] = max(max(dp[i - j] * j, (i - j) * j), dp[i]);
}
}
// 5、打印dp数组
// for (int i = 0; i < dp.size(); i++) {
// cout << i <<" : " << dp[i] << endl;
// }
return dp[n];
}
};
三、不同的搜索二叉树
1、思路:
在数据结构中有一个在公式加卡塔兰数,它可以直接推出有多少种二叉搜索数,不过他又递归的存在,所以在本题会超时,公式如下:
代码如下:
class Solution {
private:
int combination(int n, int k) {
if (k == 0 || k == n) {
return 1;
} else {
return combination(n - 1, k - 1) + combination(n - 1, k);
}
}
public:
int numTrees(int n) {
int result = combination(2 * n, n) / (n + 1);
return result;
}
};
递归思路:
这个思路也是比较抽象的。。
大致的意思是,前者的二叉树与后者的二叉树有相似之处,而且可以推出来。
大致就是这样的思路:
所以可以推出推导公式:
dp[3] = dp[0] * dp[2] + dp[1] * dp[1] + dp[2] * dp[0];
其他的内容就比较好推断了;
2、整体代码如下:
class Solution {
public:
int numTrees(int n) {
if (n == 1 || n == 0) return 1;
// 1、创建dp数组,dp[i]表示在i个节点下最多有多少种二叉搜索树
vector<int> dp(n + 1);
// 2、初始化
dp[0] = 1; // 空树也是一种
dp[1] = 1;
dp[2] = 2;
// 3、遍历顺序
for (int i = 3; i <= n; i++) {
for (int j = 0; j < i; j++) {
// 4、递推公式
dp[i] += dp[i - j - 1] * dp[j];
}
}
// 5、打印dp数组
// for (int i : dp) {
// cout << i << endl;
// }
return dp[n];
}
};
今日学习时间:1.5小时;
leave message:
A single act of kindness throws out roots inn all direction, and the roots spring up and make new trees.
translate:
一个善意的举动就像树根一样四处漫开,而且它会破土而出,长成参天大树。