整数拆分
1、递推表达式;思考dp[i]最大乘积是怎么得到的呢?
将j从1遍历到i-1
,然后有两种渠道得到dp[i];
- 一个是j * (i - j) 直接相乘。
- 一个是j * dp[i - j],相当于是拆分(i - j)。
假设求dp[10]
j | i-j(要拆分的部分) |
---|---|
1 | 9 |
2 | 8 |
3 | 7 |
4 | 6 |
5 | 5 |
6 | 4 |
-
为什么遍历到
j<=i/2
即可?
当拆分为尽可能相等的几个数的时候才使得乘积最大,故如果j=i/2+1的话,拆分i-j则会使得大小不会近似,故也不会得到乘积最大值。 -
为什么
只拆分i-j
?
求dp[i] 拆分i的时候:只要拆分中有 j 则拆分 i-j 都可以得到所有拆分i时拆分中有j的情况。 -
为什么要比较
j*(i-j)
和j*dp[i-j]
、dp[i]
?j * (i - j)
是单纯的把整数拆分为两个数相乘,而j * dp[i - j]
是拆分成两个以及两个以上的个数相乘。- 如果定义
dp[i - j] * dp[j]
也是默认将一个数强制拆成4份以及4份以上了
Ⅰ、我的AC:
class Solution {
public:
int integerBreak(int n) {
int dp[n+1];
dp[0] = 0;
dp[1] = 0;
dp[2] = 1;
for(int i=3; i<=n; i++) {
dp[i] = 0;
for(int j=1; j<=i/2; j++) {
dp[i] = max(max(j*dp[i-j],j*(i-j)), dp[i]);
}
}
return dp[n];
}
};
不同的二叉搜索树
1、递推公式
dp[i],分别以值1、2…… i为头节点,统计每种情况的二叉搜索树的个数。
头节点的值 | 左子树节点个数 | 右子树节点个数 |
---|---|---|
1 | dp[0] | dp[i-1] |
2 | dp[1] | dp[i-2] |
3 | dp[2] | dp[i-3] |
…… | ||
i | dp[i-1] | dp[0] |
2、这里以dp[3]找出了其与dp[2]和dp[1]、dp[0]的关系。
3、AC code
class Solution {
public:
int numTrees(int n) {
vector<int> dp(n+1, 0);
dp[0]=1;
for(int i=1; i<=n; i++) {
for(int j=0; j<i; j++) {
dp[i] += dp[j] * dp[i-j-1];
}
}
return dp[n];
}
};