算法训练营day41_动态规划(3.13)
343.整数拆分
这道题刚睡醒做的,刚开始试f[i]=f[j]*(i-j)没过,后来看样例发现f[j]可能比j还小,就用了max(f[j],j),过了;灵感主要是看样例,36可以拆成334,那么也可以拆成46,我求出来其中一个的f,再乘以差值;
- f[i]:表示i可以拆分得到的乘积最大值;
- f[i]=max(f[j],j)(j-i),如果i可以拆出来j(就是i>j),那么i的值就是j的值 * (i-j)或者是f[j](i-j),看谁大(因为一个数拆分得到的乘积最大值可能没有自己大);
- f(由于每个数都可以拆为1和自己-1,所以每个数都照这个初始化(不初始化也行);
- 外层循环i(3-n),内层循环j(1,i-1),j就是枚举i能拆出来的数;
class Solution {
public:
int f[60];
int integerBreak(int n) {
memset(f,0,sizeof f);
f[2]=1;
for(int i=3;i<=n;i++) f[i]=i-1;
for(int i=3;i<=n;i++){
for(int j=1;j<=i-1;j++){
f[i]=max(f[i],max(j,f[j])*(i-j));
}
}
return f[n];
}
};
96.不同的二叉搜索树
状态转移的时候,可以根据头结点为x来划分所有情况(经验之谈);头结点为x,那么左子树个数为x-1,右子树个数为总-x(利用的是二叉树左子树都小于自己,右子树都大于自己这一特性);
- f(i)表示i个节点的方案个数;
- f(i)=1-n作为头结点的方案加和,以j作为头结点的方案个数为f(j-1)*f(i-j);
- 初始化;f(0)为1;
- 外层循环i(2-n),内层循环j(1-i);
class Solution {
public:
int f[20];
int numTrees(int n) {
memset(f,0,sizeof f);
f[0]=1;
for(int i=1;i<=n;i++){
for(int j=1;j<=i;j++){
f[i]+=f[j-1]*f[i-j];
}
}
return f[n];
}
};