一、问题描述

在做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];
}

三、总结

动态规划有一个需要理解的地方就是:在这个题中,他的表并不是代表路径,而只是代表到当前位置的最小路径和,可能这个路径的结果不是最优的,并且结果很大,但是在我们最后的时候就会把它给排除掉,保证最后的总路径一定是最优的。然后就是多练一些题就可以很熟悉解法了。如果需要路径那么我们就可以倒退结果,确定当前的结果是来自哪个最短路径,这样就可以找到最短路径了。

可以参考题解中的一个精选题解还有一个解释过程很形象。可以帮助理解。

四、参考

可以参考下面的一些还不错的文章,有详细的解释:

知乎:

https://zhuanlan.zhihu.com/p/91582909

posted on 2020-08-21 20:08  蔚蓝色の天空  阅读(889)  评论(0编辑  收藏  举报