一、问题描述
在做LeetCode的时候遇到了都动态规划的问题,在维基百科中动态规划是这样解释的:
通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。动态规划常常适用于有重叠子问题和最佳子结构性质的问题,动态规划方法所耗时间往往远少于朴素解法。
二、解决
求解的的方法包括下面的两种:
①自顶向下的备忘录法
②自底向上
求解的过程方法:
在求解的过程中,我们首先需要确定求解的状态转移方程
例1:
斐波拉切数列求解的状态转移方程:
# 状态方程
f(n) = f(n-2) + f(n-1)
例2:
问题描述,出自LeetCode第64题:https://leetcode-cn.com/problems/minimum-path-sum/
给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。
说明:每次只能向下或者向右移动一步。
代码:
#include <iostream>
#include <vector>
using namespace std;
int minPathSum(vector<vector<int>> &grid); // 最小路径和
int main() {
vector<vector<int >> grids = {
{1, 3, 1},
{1, 5, 1},
{4, 2, 1}
};
cout << minPathSum(grids);
}
// 最小路径和
int minPathSum(vector<vector<int>> &grid) {
int m = grid.size();
int n = grid[0].size();
vector<vector<int>> nums(grid.size(), vector<int>(grid[0].size(), 0));
for (int l = 0; l < grid.size(); ++l) {
for (int i = 0; i < grid[0].size(); ++i) {
if (l == 0 && i == 0) { // 如果是初值就为0
grid[l][i] = grid[l][i];
continue;
} else if (l == 0) { // 如果在上边界就只能从前面的路径得到
grid[l][i] = grid[l][i] + grid[l][i - 1];
} else if (i == 0) { // 如果是下边界就只能从上面的结果得到
grid[l][i] = grid[l - 1][i] + grid[l][i];
} else { grid[l][i] = min(grid[l - 1][i], grid[l][i - 1]) + grid[l][i]; }
}
}
for (int k = 0; k < grid.size(); ++k) {
for (int i = 0; i < grid[0].size(); ++i) {
cout << " " << grid[k][i];
}
cout << endl;
}
return grid[m - 1][n - 1];
}
三、总结
动态规划有一个需要理解的地方就是:在这个题中,他的表并不是代表路径,而只是代表到当前位置的最小路径和,可能这个路径的结果不是最优的,并且结果很大,但是在我们最后的时候就会把它给排除掉,保证最后的总路径一定是最优的。然后就是多练一些题就可以很熟悉解法了。如果需要路径那么我们就可以倒退结果,确定当前的结果是来自哪个最短路径,这样就可以找到最短路径了。
可以参考题解中的一个精选题解还有一个解释过程很形象。可以帮助理解。
四、参考
可以参考下面的一些还不错的文章,有详细的解释:
知乎: