63. 不同路径 II

news/2024/11/28 15:51:27/

题目链接:力扣

 解题思路:类似于 62. 不同路径

动态规划:

  1. 定义状态:对于m*n的网络,从最后一行到右下角,以及从最后一列到右下角,都只有一条不同路径:一直向右或一直向下,所以可以定义状态:dp[i][j],表示从 (i,j) 到右下角的不同路径数量
  2. 初始状态和边界情况:
    1. 根据状态的定义,最后一行以及最后一列达到右下角的路径都只有一种,但是如果有障碍物的话,障碍物以前的格子就到达不了右下角,障碍物后面的格子可以到达右下角。
      1. 所以,初始状态为:
        1. dp[m-1][i+1,...,n-1] = 1,dp[m-1][0,...,i]=0,(m-1,i)的位置有一个障碍物,如果这一行有多个障碍物,(m-1,i)是最右边的那个障碍物
        2. dp[i+1,...,m-1][n-1] = 1,dp[0,...,i][n-1]=0, (i,n-1)的位置有一个障碍物,如果这一列有多个障碍物,(m-1,i)是最下边的那个障碍物
  3. 确定状态转移:现在最后一行和最后一列的状态已经确定,其他的状态转移如下:
    1. 根据状态的定义,从 (i,j) 到达右下角,有两种方案:
      1. 如果bstacleGrid[i][j] == 1,有障碍物,dp[i][j]=0
      2. 否则:dp[i][j] = dp[i+1][j]+dp[i][j+1]

AC代码:

class Solution {public static int uniquePathsWithObstacles(int[][] obstacleGrid) {if (obstacleGrid[0][0]==1){return 0;}int m = obstacleGrid.length;int n = obstacleGrid[0].length;int[][] dp = new int[m][n];int pos = n-1;boolean flag = true;for (;pos>=0;pos--){if (obstacleGrid[m-1][pos]==0&&flag){dp[m-1][pos] = 1;}else{flag = false;dp[m-1][pos] = 0;}}pos = m-1;flag = true;for (;pos>=0;pos--){if (obstacleGrid[pos][n-1]==0&&flag){dp[pos][n-1] = 1;}else{flag = false;dp[pos][n-1] = 0;}}for (int i = m - 2; i >= 0; i--) {for (int j = n - 2; j >= 0; j--) {if (obstacleGrid[i][j]==1){dp[i][j]=0;}else {dp[i][j] = dp[i+1][j]+dp[i][j+1];}}}return dp[0][0];}
}

上述算法的时间复杂度为O(mn),空间复杂度为O(mn) 

优化:在动态规划中,一般可以使用滚动数组进行空间优化,根据dp状态的定义,dp[i][j]只和dp[i+1][j]以及dp[i][j+1]相关,如下图所示:

在求解二维dp数组中,先求解下面一行的dp数组(从右往左),然后再求解上面一行的dp数组(也是从右往左),最终想要的目标是dp[0][0],也就是最上面一行的dp数组值,当求解完第 i 行的dp值时,此时第 i+1行的dp值就不再需要了,所以只需要一维数组就可以完成更新,每次都是对这个一维数组进行滚动更新。具体如下:

  1. int[] dp = new int[n],用来保存每一行的dp值,初始时保存最下面一行的dp值,dp[n-1]=1(已经在右下角了,路径数量为1)
  2. dp的更新过程:从最后一行往上更新(每一行中从右往左更新)
    1. 如果 bstacleGrid[i][j] == 1,当前有障碍,显然从当前位置到达不了右下角,所以dp[j] = 0
    2. 否则,如果 bstacleGrid[i][j] == 1 && j + 1 < n,此时dp[j] = dp[j] +  dp[j+1],
  3. 接下来分析为什么使用一维数组就可以完成二维更新
    1. 当在最后一行时
      1. bstacleGrid[i][j] == 1,dp[j] =0,比较容易理解,有障碍,到达不了
      2. 否则:dp[j] = dp[j]+dp[j+1],因为数组在初始化时默认为0,所以在最后一行时(除dp[n-1]外),相当于dp[j] = dp[j+1],即从(m-1,j)到右下角的路径数量等于从(m-1,j+1)到右小角的数量,显然是符合要求的
    2. 当求解倒数第二行时,此时dp[i]保存的是最后一行中每一列到右下角的路径数
      1. 如下如所示:
      2. 求解倒数第二行最后一个元素时,也就是(3,4)位置
        1. 如果bstacleGrid[3][4] == 1,dp[4] =0,比较容易理解,有障碍,到达不了
        2. 否则,因为是在最右边一列,只能向下走,所以(3,4)位置的dp值等于最后一行(4,4)位置的dp值,注意,在更新dp数组前,dp[3]保存就是(4,4)位置的dp值,所以不用更新,j+1 < n就是为了限制这种情况
      3. 求解倒数第二行的倒数第二个元素时,也就是(3,3)位置
        1. 如果bstacleGrid[3][4] == 1,dp[3] =0,比较容易理解,有障碍,到达不了
        2. 否则,可以向下走和向右走,那么此时(3,3)位置的dp值等于(3,4)位置的dp值加上(4,3)位置的dp值,因为此时dp[3]还没有更新,保存的就是(4,3)位置的dp值,而dp[4]已经更新了,保存的是(3,4)位置的dp值,所以可以直接dp[3]=dp[3]+dp[4]!可见使用一维数据的滚动更新就可完成二维数组的dp更新

AC代码:

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


http://www.ppmy.cn/news/979196.html

相关文章

华为数通HCIP-ISIS高级

isis区域间的互访 1、L2区域 to L1区域 在L1区域发布的路由会以L1-LSP在L1区域内传递&#xff0c;到达L1-2路由器时&#xff0c;L1-2路由器会将该L1-LSP转换为L2-LSP在L2区域内传递&#xff1b; 因此L2区域的设备可以学习到L1区域的明细路由&#xff0c;进行访问&#xff1b;…

2023年深圳杯数学建模B题电子资源版权保护问题

2023年深圳杯数学建模 B题 电子资源版权保护问题 原题再现&#xff1a; 版权又称著作权&#xff0c;包括发表权、署名权、修改权、保护作品完整权、复制权、发行权、出租权、展览权、表演权、放映权、广播权、信息网络传播权、摄制权、改编权、翻译权、汇编权及应当由著作权人…

Kubernetes 的核心概念:Pod、Service 和 Namespace 解析

&#x1f337;&#x1f341; 博主 libin9iOak带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——libin9iOak的博客&#x1f390; &#x1f433; 《面试题大全》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33…

7.25 Qt

制作一个登陆界面 login.pro文件 QT core guigreaterThan(QT_MAJOR_VERSION, 4): QT widgetsCONFIG c11# The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on …

python 面向对象编程的特点 - 封装 - 继承(经典类、新式类) - 多态 - 静态方法、类方法 - 下划线的使用 - 回合制攻击游戏实验

目录 面向对象编程的特点&#xff1a; 封装&#xff1a;封装是将数据和操作&#xff08;方法&#xff09;封装在一个对象中的能力 继承&#xff1a;继承是指一个类&#xff08;子类&#xff09;可以继承另一个类&#xff08;父类&#xff09;的属性和方法。 我们为什么需要继…

大数据Flink(四十九):框架版本介绍和编程语言选择

文章目录 框架版本介绍和编程语言选择 一、框架版本介绍 二、编程语言选择 框架版本介绍和编程语言选择

SQL力扣练习(七)

1.行程和用户(262) 表&#xff1a;Trips ----------------------- | Column Name | Type | ----------------------- | id | int | | client_id | int | | driver_id | int | | city_id | int | | status | enum | | reques…

猿人学第二题—混淆 动态cookie检测

猿人学第二题—混淆 动态cookie检测 1、代码格式化检测2、检测global和navigator.vendorSub3、检测setInterval思考 4、console.log输出检测补环境 简单的document.cookie&#xff0c;location.reload等就不写了 1、代码格式化检测 这里应该是利用了字符串正则匹配性能低的特点…