前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >64最小路径和----动态规划

64最小路径和----动态规划

作者头像
大忽悠爱学习
发布2021-11-15 10:15:41
3420
发布2021-11-15 10:15:41
举报
文章被收录于专栏:c++与qt学习

图解动态规划算法思想

此时可以求得最小路径和为7,

通过上面例子我们可以得出:要求的(i,j)位置的最优解,我们只需要比较该位置上方(i,j-1)和左方(i-1,j)的最优解,取最小值再加上(i,j)当前位置对应的grid数组的值即可,这样我们就得到了递归公式

代码语言:javascript
复制
class Solution {
public:
    int minPathSum(vector<vector<int>>& grid) 
    {
        int r = grid.size(); //二维数组的行
        int c = grid[0].size();//二维数组的列
        //dp数组用来存放每个位置的最优解
        vector<vector<int>> dp(r, vector<int>(c, 0));//初始化dp二维数组的大小为r行c列
        //0,0位置的最优解等于该位置
        dp[0][0] = grid[0][0];
        //计算第i行的最优解
        for (int i = 1; i < c; i++)
        {
            dp[0][i] = dp[0][i - 1] + grid[0][i];
        }
        //计算第j列的最优解
        for (int j = 1;j < r; j++)
        {
            dp[j][0] = dp[j - 1][0] + grid[j][0];
        }
        //计算第1行到第r-1行的最短路径和
        //第1列到第c-1列的最短路径和
        for (int i = 1; i < r; i++)
        {
            for (int j = 1; j < c; j++)
            {
                //位置i,j对应的最优解,应该选取左边和上面对应最优解的较小者加上当前对应grid数组中的值
                dp[i][j] = min(dp[i][j - 1],dp[i - 1][j])+grid[i][j];
            }
        }
        //返回最优解
        return dp[r - 1][c - 1];
    }
};
  • 我们看到二维数组dp和二维数组grid的长和宽都是一样的,没必要再申请一个dp数组,完全可以使用grid,来看下代码
代码语言:javascript
复制
class Solution {
public:
    int minPathSum(vector<vector<int>>& grid) 
    {
        int r = grid.size();
        int c = grid[0].size();
        for (int i = 0; i < r; i++)
        {
            for (int j = 0; j < c; j++)
            {
                if (i == 0 && j == 0)
                    continue;
                else if (i == 0)
                    grid[0][j] += grid[0][j - 1];
                else if (j == 0)
                    grid[i][0] += grid[i - 1][0];
                else
                    grid[i][j] += min(grid[i - 1][j],grid[i][j - 1]);
            }
        }
        return grid[r- 1][c- 1];
    }

};

递归解法:

  • 我们还可以把上面的动态规划改为递归,定义一个函数
  • minPathSum(int[][] grid, int i, int j)表示从左上角到坐标(i,j)的最短路径和,那么同样道理,要走到坐标(i,j)只能从上面下来或者左边过来。所以代码轮廓我们大致能写出来
  • 如果这里递归采用反向计算,那么是在回溯过程中计算重目标点到达起点的最小路径和,也被称为自下而上的递归
  • 如果是在从起点不断往终点探索过程中计算出结果,那么称为自上而下的递归
  • 这里我们从终点开始,通过不断递归到达起点,在回溯过程中计算从起点到终点的距离
代码语言:javascript
复制
public int minPathSum(int[][] grid, int i, int j) {
    if (边界条件的判断) {
        return
    }

    //一些逻辑处理

    //取从上面走下来和从左边走过来的最小值+当前坐标的值
    return grid[i][j] + Math.min(minPathSum(grid, i - 1, j), minPathSum(grid, i, j - 1));
}
  • 下面再来看下完整代码(注意这种会超时)
代码语言:javascript
复制
class Solution {
public:
    int minPathSum(vector<vector<int>>& grid) 
    {
        return FindMinPath(grid, grid.size() - 1, grid[0].size() - 1);
    }
    int FindMinPath(vector<vector<int>>& grid,int i,int j)
    {
        //到达起点,开始回溯计算
        if (i == 0 && j == 0)
        {
            return grid[i][j];
        }
        if (i == 0) //第一行只能从左边走过来
        {
            return grid[0][j] + FindMinPath(grid, i, j - 1);//前面一个点的值加上i不变,j-1
        }
        if (j == 0)//第一列只能从上面走下来
        {
            return grid[i][0] + FindMinPath(grid, i - 1, j);
        }
         //取从上面走下来和从左边走过来的最小值+当前坐标的值
        return grid[i][j] +min(FindMinPath(grid, i - 1, j),FindMinPath(grid,i,j-1));
    }
};
  • 因为这里面的递归会导致大量的重复计算,所以还是老方法,就是把计算过的值存储到一个map中,下次计算的时候先看map中是否有,如果有就直接从map中取,如果没有再计算,计算之后再把结果放到map中,可以理解为记忆化递归,来看下代码
代码语言:javascript
复制
class Solution {
public:
    int minPathSum(vector<vector<int>>& grid) 
    {
        map<pair<int, int>, int> ret;
        return FindMinPath(grid, grid.size() - 1, grid[0].size() - 1,ret);
    }
    int FindMinPath(vector<vector<int>>& grid,int i,int j, map<pair<int, int>, int>& ret)
    {
        //如果当前位置的最短路径被计算过,那就直接返回
        if (ret.count({ i,j }) == 1)
            return ret[{i, j}];
        int res;//保存当前位置的最短路径和
        //到达起点,开始回溯计算
        if (i == 0 && j == 0)
        {
            res=grid[i][j];
        }
        //如果是第一行或者第一列,那么第一行或者第一列上的点的最短路径和就是当前点的值加上它前面一个点的值
        else if (i == 0)//第一行
        {
            res=grid[0][j] + FindMinPath(grid, i, j - 1,ret);//前面一个点的值加上i不变,j-1
        }
        else if (j == 0)//第一列
        {
            res=grid[i][0] + FindMinPath(grid, i - 1, j,ret);
        }
        else
        res=grid[i][j] +min(FindMinPath(grid, i - 1, j,ret),FindMinPath(grid,i,j-1,ret));
        //保存当前位置最短路径和和位置到ret容器
        ret[{i, j}] = res;
        return res;//返回当前位置最短路径和
    }
};
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021/04/09 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 图解动态规划算法思想
  • 通过上面例子我们可以得出:要求的(i,j)位置的最优解,我们只需要比较该位置上方(i,j-1)和左方(i-1,j)的最优解,取最小值再加上(i,j)当前位置对应的grid数组的值即可,这样我们就得到了递归公式
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档