• 数据结构与算法 -- 动态规划常见问题


    一、简单的路径规划

    1、问题描述

    问题:一个机器人位于一个 m * n 网格的左上角 (起始点在下图中标记为“开始” ),机器人每次只能向下或者向右移动一步,现在机器人试图达到网格的右下角(在下图中标记为“结束”)。问总共有多少条不同的路径?

                                   

    1. 示例:
    2. 输入:m = 3, n = 2
    3. 输出: 3
    4. 解释: 从左上角开始,总共有 3 条路径可以到达右下角:
    5. 1. 向右 -> 向右 -> 向下
    6. 2. 向右 -> 向下 -> 向右
    7. 3. 向下 -> 向右 -> 向右

    2、算法分析  

    1)备忘录

            dp[i][j]表示到i行j列的格子的路径数; 

    2)初始化状态

            因为每次只能向下或者向右进行移动,所以第一行第一列的所有路径数都是1;其他格子路劲数初始化为0; 

    3)状态参数

            状态参数就是i行j列; 

    4)决策

            因为只能向下或者向右移动,因此d[i][j] = d[i-1][j] + d[i][j-1] 

    3、状态转移方程

                                

    4、算法实现

    1. package main
    2. import "fmt"
    3. func DP(m int, n int) int {
    4. // 创建备忘录
    5. dp := make([][]int, m)
    6. for i := range dp{
    7. dp[i] = make([]int, n)
    8. }
    9. // 初始化状态
    10. for i := 0; i < m; i++ {
    11. dp[i][0] = 1
    12. }
    13. for i := 0; i < n; i++ {
    14. dp[0][i] = 1
    15. }
    16. // 转移方程转换实现
    17. for i := 0; i< m; i++ {
    18. for j := 0; j < n; j++ {
    19. if i == 0 || j == 0 {
    20. dp[i][j] = 1
    21. } else {
    22. dp[i][j] = dp[i-1][j] + dp[i][j-1]
    23. }
    24. }
    25. }
    26. return dp[m-1][n-1] // 输出答案
    27. }
    28. func main() {
    29. m := 3
    30. n := 7
    31. fmt.Println(DP(m, n)) // 输出答案
    32. }

    二、带路障路径规划

    1、问题描述

    问题:一个机器人位于一个 m * n 网格的左上角 (起始点在下图中标记为“开始” )。机器人每次只能向下或者向右移动一步,现在机器人试图达到网格的右下角(在下图中标记为“结束”)。考虑网格中有障碍物,网格中的障碍物和空位置分别用 1 和 0 来表示,那么从左上角到右下角将会有多少条不同的路径?

     

    1. 示例:
    2. 输入:
    3. [
    4. [0, 0, 0],
    5. [0, 1, 0],
    6. [0, 0, 0]
    7. ]
    8. 输出: 2
    9. 解释:3 * 3 网格的正中间有一个障碍物。
    10. 从左上角到右下角一共有 2 条不同的路径:
    11. 1. 向右 -> 向右 -> 向下 -> 向下
    12. 2. 向下 -> 向下 -> 向右 -> 向右

     2、算法分析  

    1)备忘录

             dp[i][j]表示到i行j列的格子的路径数; 

    2)初始化状态

            依然先考虑网格的第一行和第一列,第一行永远只能从左侧的格子往前走;第一列永远只能从上方的格子往下走。由于我们只能向右或向下走,所以第一行和第一列的格子永远只能存在 1 条路径。但是,我们还需要再考虑那些有障碍的格子,对这些格子来说,它们的路径总数应该是 0 而不是 1。

    3)状态参数

            状态参数就是i行j列; 状态参数依然是格子的行数和列数;

    4)决策

              因为只能向下或者向右移动,因此d[i][j] = d[i-1][j] + d[i][j-1] ;有障碍物的格子的路径数为0;

    3、状态转移方程

     

    4、算法实现

    1. package main
    2. import "fmt"
    3. func DP(m int, n int, array [][]int) int {
    4. // 创建备忘录
    5. dp := make([][]int, m)
    6. for i := range dp{
    7. dp[i] = make([]int, n)
    8. }
    9. // 初始化状态
    10. for i := 0; i < m; i++ {
    11. if array[i][0] == 1 {
    12. dp[i][0] = 0
    13. } else {
    14. dp[i][0] = 1
    15. }
    16. }
    17. for i := 0; i < n; i++ {
    18. if array[0][i] == 1 {
    19. dp[0][i] = 0
    20. } else {
    21. dp[0][i] = 1
    22. }
    23. }
    24. // 转移方程转换实现
    25. for i := 0; i< m; i++ {
    26. for j := 0; j < n; j++ {
    27. if (i == 0 || j == 0) && array[i][j] == 0 {
    28. dp[i][j] = 1
    29. } else if array[i][j] == 1 {
    30. dp[i][j] = 0
    31. } else {
    32. dp[i][j] = dp[i-1][j] + dp[i][j-1]
    33. }
    34. }
    35. }
    36. return dp[m-1][n-1] // 输出答案
    37. }
    38. func main() {
    39. m := 3
    40. n := 3
    41. array := [][]int{{0, 0, 0},
    42. {0, 1, 0},
    43. {0, 0, 0}}
    44. fmt.Println(DP(m, n, array)) // 输出答案
    45. }

    三、跳跃游戏

    1、问题描述

    题目:给出一个非负整数数组 A,你最初定位在数组的第一个位置。数组中的每个元素代表你在那个位置可以跳跃的最大长度。判断你是否能到达数组的最后一个位置。 

    1. 示例1
    2. 输入:A = [2, 3, 1, 1, 6]
    3. 输出: True
    4. 解释: 我们可以先跳 1 步,从位置 0 到达位置 1, 然后再从位置 13 步到达最后一个位置。

    2、算法分析  

    1)备忘录

             DP[i] 来表示能否从出发点到达位置 i。 

    2)初始化状态

            初始化状态就是 0 这个位置。因为这个位置是出发点,因此肯定可以到达,所以我们可以将其初始化成 True。 

    3)状态参数

            状态参数也比较容易看出,只有数组的位置是变化的,因此状态参数就是当前位置 i 

    4)决策

            要知道能否到达位置 i,就需要逐个看前面的位置,判定能否从位置 i−1、i−2、i−3 … 跳到位置 i 上。 

    3、状态转移方程

     

    4、算法实现

    1. package main
    2. import "fmt"
    3. func DP(array []int) bool {
    4. length := len(array)
    5. // 创建备忘录
    6. dp := make([]bool, length)
    7. // 初始化状态
    8. for i := 0; i < length; i++ {
    9. dp[i] = false
    10. }
    11. dp[0] = true
    12. // 转移方程转换实现
    13. for i := 1; i< length; i++ {
    14. for j := 0; j < i; j++ {
    15. if dp[j] && j + array[j] >= i {
    16. dp[i] = true
    17. break
    18. }
    19. }
    20. }
    21. return dp[length-1] // 输出答案
    22. }
    23. func main() {
    24. array := []int{2, 3, 1, 1, 6}
    25. fmt.Println(DP(array)) // 输出答案
    26. }

     

    声明:本文参考极客时间《动态规划面试宝典》

  • 相关阅读:
    大数据毕业设计选题推荐-污水处理大数据平台-Hadoop-Spark-Hive
    并查集的原理+例题
    进阶必看:一文搞懂中台战略与企业架构关系
    IntelliJ IDEA Dev 容器
    小程序怎么做?个人小程序怎么做?新手教程
    docker安装flink
    K8S容器内安装cur/telnet命令(Alpine Linux离线环境安装curl/telnet或其他工具)
    VScode如何调节编辑器字体大小
    计算机网络性能
    找不到实时聊天软件?给你推荐电商企业都在用的!
  • 原文地址:https://blog.csdn.net/u012967763/article/details/126615014