注:以下代码均为c++
文章目录
动态规划的本质:用数组保存之前算过的值,在计算后面的值时直接从数组中取已经算过的值再继续计算,以此减少重复计算。
1. 最大子数组和

思路:

int maxSubArray(vector<int>& nums) {
int res = INT_MIN, f = 0;
for(int i = 0; i < nums.size(); i++){
f = max(f, 0) + nums[i];
res = max(f, res);
}
return res;
}
2. 三角形最小路径和

思路:

法1:用nxn的二维数组记录已经求过的结果
int minimumTotal(vector<vector<int>>& triangle){
int n = triangle.size();
vector<vector<int>> f(n,vector<int>(n)); //高维vector初始化:nxn的二维数组
f[0][0] = triangle[0][0];
for(int i = 1; i < n; i++){
for(int j = 0; j <= i; j++){
if(j-1 >= 0 && j < i)
f[i][j] = min(f[i-1][j-1], f[i-1][j]) + triangle[i][j];
else if(j-1 < 0)
f[i][j] = f[i-1][j] + triangle[i][j];
else
f[i][j] = f[i-1][j-1] + triangle[i][j];
}
}
int mins = INT_MAX;
for(int i = 0; i < n; i++){
mins = min(mins, f[n-1][i]);
}
return mins;
}
法2:优化:用2xn的二维数组(只记录上一层结果)记录已经求过的结果
int minimumTotal(vector<vector<int>>& triangle){
int n = triangle.size();
vector<vector<int>> f(2,vector<int>(n)); //优化:由于只需要记录上一层的结果,所以开两层数组即可。
f[0][0] = triangle[0][0];
for(int i = 1; i < n; i++){
for(int j = 0; j <= i; j++){
if(j-1 >= 0 && j < i)
f[i & 1][j] = min(f[i-1 & 1][j-1], f[i-1 & 1][j]) + triangle[i][j]; //n%2相当于&1
else if(j-1 < 0)
f[i & 1][j] = f[i-1 & 1][j] + triangle[i][j];
else
f[i & 1][j] = f[i-1 & 1][j-1] + triangle[i][j];
}
}
int mins = INT_MAX;
for(int i = 0; i < n; i++){
mins = min(mins, f[n-1 & 1][i]);
}
return mins;
}
3. 不同路径2


思路:
状态表示:f[i][j]:当前路径的数量
状态计算:f[i][j] = f[i-1][j] + f[i][j-1]
下面的代码一个是我自己写的,一个是答案,思路是一样的。
//我自己写的代码
int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid){
int m = obstacleGrid.size(), n = obstacleGrid[0].size();
vector<vector<int>> f(m, vector<int>(n));
for(int i = 0; i < m; i++){
for(int j = 0; j < n; j++){
if(obstacleGrid[i][j] == 1) continue; //如果是障碍物,跳过
if(i == 0 && j == 0) f[i][j] = 1; //如果是左上角赋值为1
if(i == 0 && j-1 >= 0) f[i][j] = f[i][j-1]; //第一行
if(j == 0 && i-1 >= 0) f[i][j] = f[i-1][j]; //第一列
if(i-1 >= 0 && j-1 >= 0) f[i][j] = f[i][j-1] + f[i-1][j];
}
}
return f[m-1][n-1];
}
//答案
int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
int m = obstacleGrid.size(), n = obstacleGrid[0].size();
vector<vector<int>> f(m, vector<int>(n));
for(int i = 0; i < m; i++){
for(int j = 0; j < n; j++){
if(obstacleGrid[i][j]) //如果是障碍物,跳过
continue;
if(i == 0 && j == 0) f[i][j] = 1; //如果是左上角
if(i > 0) f[i][j] += f[i-1][j]; //如果不是第一行
if(j > 0) f[i][j] += f[i][j-1]; //如果不是第一列
}
}
return f[m-1][n-1];
}

博客主要围绕动态规划算法展开,介绍了其本质是用数组保存已算值以减少重复计算。详细阐述了最大子数组和、三角形最小路径和、不同路径2等多个经典问题的思路,还涉及买卖股票最佳时机、背包问题(包括01背包和完全背包)等,给出了状态表示和计算方法。

被折叠的 条评论
为什么被折叠?



