对于动态规划问题,如下五步曲,这五步都搞清楚了,才能说把动态规划真的掌握了!
- 确定dp数组(dp table)以及下标的含义
- 确定递推公式
- dp数组如何初始化
- 确定遍历顺序
- 举例推导dp数组
70 爬楼梯
class Solution {
public:
int climbStairs(int n) {
if(n<=1) return n;
vector<int>dp(n+1);
dp[1]=1;
dp[2]=2;
for(int i=3;i<=n;i++){
dp[i]=dp[i-1]+dp[i-2];
}
return dp[n];
}
};
class Solution {
public:
int climbStairs(int n) {
if(n<=1) return n;
vector<int>dp(n+1);
dp[1]=1;
dp[2]=2;
for(int i=3;i<=n;i++){
int sum=dp[1]+dp[2];
dp[1]=dp[2];
dp[2]=sum;
}
return dp[2];
}
};
198 打家劫舍
class Solution {
public:
int rob(vector<int>& nums) {
int len=nums.size();
vector<int>dp(len+1);
if(len==0) return 0;
if(len==1) return nums[0];
if(len==2) return max(nums[0],nums[1]);
dp[0]=nums[0];
dp[1]=max(nums[0],nums[1]);
for(int i=2;i<len;i++){
dp[i]=max(dp[i-2]+nums[i],dp[i-1]);
}
return dp[len-1];
}
};
class Solution {
public:
int rob(vector<int>& nums) {
int pre2=0;
int pre1=0;
for(int i=0;i<nums.size();i++){
int cur=max(pre2+nums[i],pre1);
pre2=pre1;
pre1=cur;
}
return pre1;
}
};
213 打家劫舍2
class Solution {
public:
int rob(vector<int>& nums) {
int len=nums.size();
vector<int>dp(len);
if(len==0) return 0;
if(len==1) return nums[0];
if(len==2) return max(nums[0],nums[1]);
dp[0]=nums[0];
dp[1]=max(nums[0],nums[1]);
for(int i=2;i<len-1;i++){
dp[i]=max(dp[i-2]+nums[i],dp[i-1]);
}
int res=dp[len-2];
dp[1]=nums[1];
dp[2]=max(nums[1],nums[2]);
for(int i=3;i<len;i++){
dp[i]=max(dp[i-2]+nums[i],dp[i-1]);
}
res=max(res,dp[len-1]);
return res;
}
};
class Solution {
public:
int robline(vector<int>&nums,int first,int last){
int pre2=0, pre1=0;
for(int i=first;i<=last;i++){
int cur = max(pre2+nums[i],pre1);
pre2=pre1;
pre1=cur;
}
return pre1;
}
int rob(vector<int>& nums) {
int n=nums.size();
if(n==0) return 0;
if(n==1) return nums[0];
return max(robline(nums,0,n-2),robline(nums,1,n-1));
}
};
64.最小路径和
class Solution {
public:
int minPathSum(vector<vector<int>>& grid) {
if(grid.size()==0||grid[0].size()==0) return 0;
int m=grid.size(),n=grid[0].size();
int dp[m][n];
dp[0][0]=grid[0][0];
for(int j=1;j<n;j++){
dp[0][j]=dp[0][j-1]+grid[0][j];
}
for(int i=1;i<m;i++){
dp[i][0]=dp[i-1][0]+grid[i][0];
}
for(int i = 1;i<m;i++){
for(int j=1;j<n;j++){
dp[i][j]=min(dp[i-1][j],dp[i][j-1])+grid[i][j];
}
}
return dp[m-1][n-1];
}
};
62 不同路径
class Solution {
public:
int uniquePaths(int m, int n) {
if(m==0||n==0) return 0;
int dp[m][n];
dp[0][0]=1;
for(int i=1;i<m;i++){
dp[i][0]=1;
}
for(int j=1;j<n;j++){
dp[0][j]=1;
}
for(int i=1;i<m;i++){
for(int j=1;j<n;j++){
dp[i][j]=dp[i-1][j]+dp[i][j-1];
}
}
return dp[m-1][n-1];
}
};
413 等差数列划分
dp[i] 表示以 A[i] 为结尾的等差递增子区间的个数。
dp[i]表示数组A[0, i]相比于A[0, i-1]多出来的等差数列的个数。注意是多出来的等差数列,所以最终的结果是每一位上dp[i]相加得到的结果。
class Solution {
public:
int numberOfArithmeticSlices(vector<int>& A) {
int len=A.size();
if(len<3) return 0;
int dp[len];
memset(dp,0,sizeof(dp));
int sum=0;
for(int i=2;i<len;i++){
if(A[i]-A[i-1]==A[i-1]-A[i-2]){
dp[i]=dp[i-1]+1;
sum+=dp[i];
}
}
return sum;
}
};
343 整数拆分
class Solution {
public:
int integerBreak(int n) {
vector<int>dp(n+1);
dp[2]=1;
for(int i=3;i<=n;i++){
for(int j=1;j<i;j++){
dp[i]=max(dp[i],max(j*(i-j),j*dp[i-j]));
}
}
return dp[n];
}
};