搞定动态规划系列(二):路径问题

138 阅读1分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第6天,点击查看活动详情

不同路径

本题是力扣62题,求不同路径

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

  • 拿到这个题,可以先找出对应的状态转移方程:dp[i][j]=dp[i-1][j]+dp[i][j-1]

动态规划求解如下:(时间复杂度mn,空间复杂度mn)

function uniquePaths (m, n) {
    let dp = new Array(m).fill(0).map(() => new Array(n).fill(0))
    for (let i = 0; i < m; i++) {
      dp[i][0] = 1
    }
    for (let j = 0; j < n; j++) {
      dp[0][j] = 1
    }
    for (let i = 1; i < m; i++) {
        for (let j = 1; j < n; j++) {
           dp[i][j] = dp[i-1][j] + dp[i][j-1]
        }
    }
    return dp[m-1][n-1]
};

image.png

看到这个击败人数,就知道此方案有些垃圾。那我们就优化一下

状态压缩,空间复杂度优化如下:(时间复杂度mn,空间复杂度n)

这里的优化其实是每次存储当前位置和上一个位置即可。

function uniquePaths (m, n) {
    let cur = new Array(n).fill(1)
    for (let i = 1; i < m; i++) {
        for (let j = 1; j < n; j++) {
           cur[j] = cur[j-1] + cur[j]
        }
    }
    return cur[n-1]
};

image.png

三角形的最小路径和

本题是力扣120题

题目: 给定一个三角形 triangle ,找出自顶向下的最小路径和。

每一步只能移动到下一行中相邻的结点上。相邻的结点 在这里指的是 下标 与 上一层结点下标 相同或者等于 上一层结点下标 + 1 的两个结点。也就是说,如果正位于当前行的下标 i ,那么下一步可以移动到下一行的下标 i 或 i + 1 。

  • 拿到这个题,我们首先可以找到对应的状态转移方程,即为dp[i][j] = Math.min(dp[i+1][j],dp[i+1][j+1]) + triangle[i][j]
function minimumTotal (triangle) {
   let n = triangle.length
   if (!n) {
       return 0
   }
   let dp = new Array(n)
   // 初始化二维数组dp
   for (let i = 0; i < n; i++) {
       dp[i] = new Array(triangle[i].length)
   }
   // 最后一层可以初始化数据
   for (let j = 0; j < triangle[n-1].length; j++) {
        dp[n-1][j] = triangle[n-1][j]
    }
   // 处理转移子问题,自底向上
   for (let i = n - 2; i >= 0; i--) {
       for (let j = 0; j < triangle[i].length; j++) {
           dp[i][j] = Math.min(dp[i+1][j], dp[i+1][j+1]) + triangle[i][j]
       }
   }
   return dp[0][0]
};

image.png

和上题一样,我们可以状态压缩,节省空间复杂度:

function minimumTotal (triangle) {
   let n = triangle.length
   if (!n) {
       return 0
   }
   let dp = []
   // 最后一层可以初始化数据
   for (let j = 0; j < triangle[n-1].length; j++) {
        dp[j] = triangle[n-1][j]
    }
   // 处理转移子问题,自底向上
   for (let i = n - 2; i >= 0; i--) {
       for (let j = 0; j < triangle[i].length; j++) {
           dp[j] = Math.min(dp[j], dp[j+1]) + triangle[i][j]
       }
   }
   return dp[0]
};

image.png