【算法优选】 动态规划之路径问题——壹

简介: 【算法优选】 动态规划之路径问题——壹


🎋前言

动态规划相关题目都可以参考以下五个步骤进行解答:

  1. 状态表⽰
  2. 状态转移⽅程
  3. 初始化
  4. 填表顺序
  5. 返回值

后面题的解答思路也将按照这五个步骤进行讲解。

🎋不同路径

🚩题目描述:

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。

机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。

问总共有多少条不同的路径?

  • 示例 1:

    输入:m = 3, n = 7
    输出:28
  • 示例 2:
    输入:m = 3, n = 2
    输出:3
    解释:
    从左上角开始,总共有 3 条路径可以到达右下角。
    1.向右 -> 向下 -> 向下
    2.向下 -> 向下 -> 向右
    3.向下 -> 向右 -> 向下
  • 示例 3:
    输入:m = 7, n = 3
    输出:28
  • 示例 4:
    输入:m = 3, n = 3
    输出:6
class Solution {
    public int uniquePaths(int m, int n) {
    }
}

🚩算法思路:

  1. 状态表⽰:对于这种「路径类」的问题,我们的状态表⽰⼀般有两种形式:
  • 从 [i, j] 位置出发,进行一系列操作;
  • 从起始位置出发,到达 [i, j] 位置,进行一系列操作。
  • 这⾥选择第⼆种定义状态表⽰的⽅式:
  • dp[i][j] 表⽰:⾛到 [i, j] 位置处,⼀共有多少种⽅式。
  1. 状态转移⽅程:简单分析⼀下。如果 dp[i][j] 表⽰到达 [i, j] 位置的⽅法数,那么到达 [i, j] 位置之前的⼀⼩步,有两种情况:
  • 从 [i, j] 位置的上⽅( [i - 1, j] 的位置)向下⾛⼀步,转移到 [i, j] 位置;
  • 从 [i, j] 位置的左⽅( [i, j - 1] 的位置)向右⾛⼀步,转移到 [i, j] 位置。
  • 由于我们要求的是有多少种⽅法,因此状态转移⽅程就呼之欲出了:
  • dp[i][j] = dp[i - 1] [j] + dp[i][j - 1] 。
  1. 初始化:可以在最前⾯加上⼀个「辅助结点」,帮助我们初始化。使⽤这种技巧要注意两个点:
  • 辅助结点⾥⾯的值要「保证后续填表是正确的」;
  • 「下标的映射关系」。
    在本题中,「添加⼀⾏」,并且「添加⼀列」后,只需将 dp[0][1] 的位置初始化为 1 即可。
  1. 填表顺序:
    根据「状态转移⽅程」的推导来看,填表的顺序就是「从上往下」填每⼀⾏,在填写每⼀⾏的时候「从左往右」。
  2. 返回值:
    根据「状态表⽰」,我们要返回 dp[m][n] 的值

🚩代码实现

class Solution {
  public int uniquePaths(int m, int n) {
    // 1. 创建 dp 表
    // 2. 初始化
    // 3. 填表
    // 4. 返回值
    int[][] dp = new int[m + 1][n + 1];
    dp[0][1] = 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][n];
  }
}

🎋不同路径二

🚩题目描述

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。

机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish”)。

现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?

网格中的障碍物和空位置分别用 1 和 0 来表示。

  • 示例 1:

    输入:obstacleGrid = [[0,0,0],[0,1,0],[0,0,0]]
    输出:2
    解释:3x3 网格的正中间有一个障碍物。
    从左上角到右下角一共有 2 条不同的路径:
    1.向右 -> 向右 -> 向下 -> 向下
    2.向下 -> 向下 -> 向右 -> 向右
  • 示例 2

    输入:obstacleGrid = [[0,1],[0,0]]
    输出:1
class Solution {
    public int uniquePathsWithObstacles(int[][] obstacleGrid) {
    }
}

🚩算法思路

本题为不同路径的变型,只不过有些地⽅有「障碍物」,只要在「状态转移」上稍加修改就可解决。

  1. 状态表⽰:对于这种「路径类」的问题,我们的状态表⽰⼀般有两种形式:
  • 从 [i, j] 位置出发,进行一系列操作;
  • 从起始位置出发,到达 [i, j] 位置,进行一系列操作。

这⾥选择第⼆种定义状态表⽰的⽅式:dp[i][j] 表⽰:⾛到 [i, j] 位置处,⼀共有多少种⽅式。

  1. 状态转移:简单分析⼀下。如果 dp[i][j] 表⽰到达 [i, j] 位置的⽅法数,那么到达 [i, j] 位置之前的⼀⼩步,有两种情况:
  • 从 [i, j] 位置的上⽅( [i - 1, j] 的位置)向下⾛⼀步,转移到 [i, j] 位置;
  • 从 [i, j] 位置的左⽅( [i, j - 1] 的位置)向右⾛⼀步,转移到 [i, j] 位置。

但是, [i - 1, j] 与 [i, j - 1] 位置都是可能有障碍的,此时从上⾯或者左边是不可能到达 [i, j] 位置的,也就是说,此时的⽅法数应该是0。

由此我们可以得出⼀个结论,只要这个位置上「有障碍物」,那么我们就不需要计算这个位置上的值,直接让它等于 0 即可。

  1. 初始化:可以在最前⾯加上⼀个「辅助结点」,帮助我们初始化。使⽤这种技巧要注意两个点:
  • 辅助结点⾥⾯的值要「保证后续填表是正确的」;
  • 「下标的映射关系」。

在本题中,添加⼀⾏,并且添加⼀列后,只需将 dp[1][0] 的位置初始化为 1 即可。

  1. 填表顺序:
    根据「状态转移」的推导,填表的顺序就是「从上往下」填每⼀⾏,每⼀⾏「从左往右」。
  2. 返回值:
    根据「状态表⽰」,我们要返回的结果是 dp[m][n]

🚩代码实现

class Solution {
    public int uniquePathsWithObstacles(int[][] obstacleGrid) {
        int m = obstacleGrid.length;
        int n = obstacleGrid[0].length;
        int[][] dp = new int[m + 1][n + 1];
        dp[0][] = 1;
        for(int i = 1; i <= m ; i++) {
            for(int j = 1; j <= n; j++) {
                if(obstacleGrid[i - 1][j - 1] == 0) {
                    dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
                }
            }
        }
        return dp[m][n];
    }
}

🌲珠宝的最高价值

🚩题目描述

现有一个记作二维矩阵 frame 的珠宝架,其中 frame[i][j] 为该位置珠宝的价值。拿取珠宝的规则为:

只能从架子的左上角开始拿珠宝

每次可以移动到右侧或下侧的相邻位置

到达珠宝架子的右下角时,停止拿取

注意:珠宝的价值都是大于 0 的。除非这个架子上没有任何珠宝,比如 frame = [[0]]。

  • 示例 1:
    输入: frame = [[1,3,1],[1,5,1],[4,2,1]]
    输出: 12
    解释: 路径 1→3→5→2→1 可以拿到最高价值的珠宝
class Solution {
    public int jewelleryValue(int[][] frame) {
        
    }
}

🚩算法思路:

  1. 状态表⽰:对于这种「路径类」的问题,我们的状态表⽰⼀般有两种形式:
  • 从 [i, j] 位置出发,进行一系列操作;
  • 从起始位置出发,到达 [i, j] 位置,进行一系列操作。

这⾥选择第⼆种定义状态表⽰的⽅式:

dp[i][j] 表⽰:⾛到 [i, j] 位置处,此时的最⼤价值。

  1. 状态转移⽅程:对于 dp[i][j] ,我们发现想要到达 [i, j] 位置,有两种⽅式:
  • 从 [i, j] 位置的上⽅ [i - 1, j] 位置,向下⾛⼀步,此时到达 [i, j] 位置能拿到的礼物价值为 dp[i - 1][j] + grid[i][j] ;
  • 从 [i, j] 位置的左边 [i, j - 1] 位置,向右⾛⼀步,此时到达 [i, j] 位置能拿到的礼物价值为 dp[i][j - 1] + grid[i][j]

我们要的是最⼤值,因此状态转移⽅程为:dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) + grid[i][j] 。

  1. 初始化:可以在最前⾯加上⼀个「辅助结点」,帮助我们初始化。使⽤这种技巧要注意两个点:
  • 辅助结点⾥⾯的值要「保证后续填表是正确的」;
  • 「下标的映射关系」。

在本题中,「添加⼀⾏」,并且「添加⼀列」后,所有的值都为 0 即可。

  1. 填表顺序:
    根据「状态转移⽅程」,填表的顺序是「从上往下填写每⼀⾏」,「每⼀⾏从左往右」。
  2. 返回值:
    根据「状态表⽰」,我们应该返回 dp[m][n] 的值。

🚩代码实现

class Solution {
    public int jewelleryValue(int[][] grid) {
        int m = grid.length;
        int n = grid[0].length;
        int[][] dp = new int[m + 1][n + 1];
        for(int i = 1; i <= m; i++)
            for(int j = 1; j <= n; j++)
                dp[i][j] = Math.max(dp[i][j - 1], dp[i - 1][j]) + grid[i - 1][j-1];
        return dp[m][n];
    }
}

⭕总结

关于《【算法优选】 动态规划之路径问题——壹》就讲解到这儿,感谢大家的支持,欢迎各位留言交流以及批评指正,如果文章对您有帮助或者觉得作者写的还不错可以点一下关注,点赞,收藏支持一下!

相关文章
|
13天前
|
算法 Python
在Python编程中,分治法、贪心算法和动态规划是三种重要的算法。分治法通过将大问题分解为小问题,递归解决后合并结果
在Python编程中,分治法、贪心算法和动态规划是三种重要的算法。分治法通过将大问题分解为小问题,递归解决后合并结果;贪心算法在每一步选择局部最优解,追求全局最优;动态规划通过保存子问题的解,避免重复计算,确保全局最优。这三种算法各具特色,适用于不同类型的问题,合理选择能显著提升编程效率。
30 2
|
1月前
|
算法
动态规划算法学习三:0-1背包问题
这篇文章是关于0-1背包问题的动态规划算法详解,包括问题描述、解决步骤、最优子结构性质、状态表示和递推方程、算法设计与分析、计算最优值、算法实现以及对算法缺点的思考。
68 2
动态规划算法学习三:0-1背包问题
|
1月前
|
数据采集 监控 安全
厂区地图导航制作:GIS技术与路径导航算法融合
在智能化、数字化时代,GIS技术为厂区的运营管理带来了革命性变化。本文探讨了如何利用GIS技术,通过数据采集、地图绘制、路径规划、位置定位和信息查询等功能,打造高效、精准的智能厂区地图导航系统,提升企业的竞争力和管理水平。
49 0
厂区地图导航制作:GIS技术与路径导航算法融合
|
1月前
|
算法
动态规划算法学习四:最大上升子序列问题(LIS:Longest Increasing Subsequence)
这篇文章介绍了动态规划算法中解决最大上升子序列问题(LIS)的方法,包括问题的描述、动态规划的步骤、状态表示、递推方程、计算最优值以及优化方法,如非动态规划的二分法。
65 0
动态规划算法学习四:最大上升子序列问题(LIS:Longest Increasing Subsequence)
|
1月前
|
算法
动态规划算法学习二:最长公共子序列
这篇文章介绍了如何使用动态规划算法解决最长公共子序列(LCS)问题,包括问题描述、最优子结构性质、状态表示、状态递归方程、计算最优值的方法,以及具体的代码实现。
123 0
动态规划算法学习二:最长公共子序列
|
1月前
|
存储 算法
动态规划算法学习一:DP的重要知识点、矩阵连乘算法
这篇文章是关于动态规划算法中矩阵连乘问题的详解,包括问题描述、最优子结构、重叠子问题、递归方法、备忘录方法和动态规划算法设计的步骤。
101 0
|
28天前
|
算法 安全 数据安全/隐私保护
基于game-based算法的动态频谱访问matlab仿真
本算法展示了在认知无线电网络中,通过游戏理论优化动态频谱访问,提高频谱利用率和物理层安全性。程序运行效果包括负载因子、传输功率、信噪比对用户效用和保密率的影响分析。软件版本:Matlab 2022a。完整代码包含详细中文注释和操作视频。
|
5天前
|
算法 数据安全/隐私保护 索引
OFDM系统PAPR算法的MATLAB仿真,对比SLM,PTS以及CAF,对比不同傅里叶变换长度
本项目展示了在MATLAB 2022a环境下,通过选择映射(SLM)与相位截断星座图(PTS)技术有效降低OFDM系统中PAPR的算法实现。包括无水印的算法运行效果预览、核心程序及详尽的中文注释,附带操作步骤视频,适合研究与教学使用。
|
13天前
|
算法 数据挖掘 数据安全/隐私保护
基于FCM模糊聚类算法的图像分割matlab仿真
本项目展示了基于模糊C均值(FCM)算法的图像分割技术。算法运行效果良好,无水印。使用MATLAB 2022a开发,提供完整代码及中文注释,附带操作步骤视频。FCM算法通过隶属度矩阵和聚类中心矩阵实现图像分割,适用于灰度和彩色图像,广泛应用于医学影像、遥感图像等领域。
|
14天前
|
算法 调度
基于遗传模拟退火混合优化算法的车间作业最优调度matlab仿真,输出甘特图
车间作业调度问题(JSSP)通过遗传算法(GA)和模拟退火算法(SA)优化多个作业在并行工作中心上的加工顺序和时间,以最小化总完成时间和机器闲置时间。MATLAB2022a版本运行测试,展示了有效性和可行性。核心程序采用作业列表表示法,结合遗传操作和模拟退火过程,提高算法性能。
下一篇
无影云桌面