动态规划:将原问题拆解成若干子问题,同时保存子问题的答案,使得每个子问题只求解一次,最终获得原问题的答案
大部分动态规划问题本质上都是递归问题,只是在递归的过程中,会发现所谓的“重叠子问题”和“最优子结构”(通过求子问题的最优解,可以获得原问题的最优解)
对于同时拥有重叠子问题和最优子结构的问题,考虑两种解决方式:1、记忆化搜索(自顶向下解决问题,较容易实现) 2、动态规划(自底向上解决问题,代码更加简洁)
解题思路:研究递归结构->使用记忆化搜索->使用动态规划
class Solution {//记忆化搜索
private:
vector<int> memo;
//将n进行分割(至少分割两部分),可以获得的最大乘积
int breakInteger(int n){
if(n == 1)
return 1;
if(memo[n] != -1)
return memo[n];
int res = -1;//res存储最大乘积
for(int i = 1; i <= n; i++)
//i + (n-i)
res = max(res, max(i*breakInter(n-i), i*(n-i)));//注意要分为两种情况,一种是只分成两个部分i和n-i,另一种i和递归breakInteger(n-i)
memo[n] = res;
return res;
}
public:
int integerBreak(int n) {
memo = vector<int>(n+1, -1);//将数组中的数字全部赋值为-1
return breakInteger(n);
}
};
class Solution {//动态规划
public:
int integerBreak(int n) {
vector<int> memo(n+1, -1);//将数组中的数字全部赋值为-1
memo[1] = 1;//自底向上解决问题
for(int i = 2; i <= n; i++)
//求解memo[i]
for(int j = 1; j <= i-1; j++)//j的值最小为1,最大为i-1
//j + (i-j)
memo[i] = max(memo[i], max(j*(i-j), j*memo[i-j]));//由于i-j < i,所以memo[i-j]一定已经存在
return memo[n];
}
};
/*具有重叠子问题,使用动态规划方法解决问题*/
class Solution {
public:
int climbStairs(int n) {
vector<int> memo(n+1, -1);
memo[1] = 1;//只有一节台阶时,存在一种方法
memo[2] = 2;//有两节台阶时,存在两种方法
for(int i = 3; i <= n; i++)//有三节以上的台阶时,方法数为最近一步采取走两节或者走一节台阶的方法数总和
memo[i] = memo[i-1] + memo[i-2];
return memo[n];
}
};