首页 > 编程语言 >算法力扣刷题记录 七十七【63. 不同路径 II】

算法力扣刷题记录 七十七【63. 不同路径 II】

时间:2024-08-12 11:26:01浏览次数:17  
标签:力扣 obstacleGrid 初始化 int II ++ 63 障碍物 dp

前言

动态规划第6篇。记录 七十七【63. 不同路径 II】


一、题目阅读

一个机器人位于一个 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

提示:

m == obstacleGrid.length
n == obstacleGrid[i].length
1 <= m, n <= 100
obstacleGrid[i][j] 为 0 或 1

二、尝试实现

分析题目,确定方法

  1. 记录 七十四【62.不同路径】与这道题类似,只不过本题的网格中多了障碍物,无法通过。这属于“跳房子”、“爬楼梯”类型的题目,所以是状态转移类型,有状态转移公式,应该用动态规划完成。

动态规划实现

  1. 第一步:确定dp数组含义和下标含义。定义一个二维数组dp[i][j],对应网络二维图形。数组含义:到第i+1行第j+1列有dp[i][j]条路径
  2. 第二步:确定状态转移公式。dp[i][j] = dp[i-1][j] + dp[i][j-1];第一个加数代表向下走一步,第二个加数代表向右走一步。但是障碍物的地方怎么处理呢?
  • 如下图,蓝色方格和黄色方格是紧挨着障碍物的网格。其余位置的上方和左方没有障碍物,所以递推公式同样适用。
  • 蓝色方格只能从上放向下一步,左侧无法通过;黄色方格只能从左向右一步,上方无法通过。
  • 如此dp[1][1]障碍物的位置dp值为0,作为加数并不影响状态方程。
  • 所以:对于有障碍物的网格,dp = 0.
    在这里插入图片描述
  1. 第三步:确定初始化。没有障碍物时,初始化第一行和第一列,dp =1;有障碍物时:
  • 如果是空位置,dp可以和前一个相等。
  • 如果遇到障碍物,dp =0;
  • 所以逻辑如下:第一行和第一列同一个道理。
  • (可能初次做题会按照没有障碍物的情况初始化,但是提交用例不通过,就需要重新改正)
	for(int i = 0;i < m;i++){//初始化第一列
            if(i > 0 && obstacleGrid[i][0] == 0){//没有障碍物的地方
                    dp[i][0] = dp[i-1][0];
            }else if(obstacleGrid[i][0] == 1){
                dp[i][0] = 0;
            }else{
                dp[i][0] = 1;
            }
        }

在这里插入图片描述
4. 遍历顺序:从递推公式知道,从前往后,从上到下。

代码实现

class Solution {
public:
    int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
        int result;//返回值
        int m = obstacleGrid.size();//有m行
        int n = obstacleGrid[0].size();//有n列
        //定义dp[i][j]数组。含义是到第i+1行第j+1列有有dp[i][j]条路径。遇到障碍物的地方dp[i][j]=0.代表该位置无妨通过。
        vector<vector<int>> dp(m,vector<int> (n,0));//建立数组是初始化为0;

        //dp初始化.
        for(int i = 0;i < m;i++){//初始化第一列
            if(i > 0 && obstacleGrid[i][0] == 0){//没有障碍物的地方
                    dp[i][0] = dp[i-1][0];
            }else if(obstacleGrid[i][0] == 1){
                dp[i][0] = 0;
            }else{
                dp[i][0] = 1;
            }
        }
        for(int i = 0;i < n;i++){//初始化第一行
            if(i >0 && obstacleGrid[0][i] == 0){//没有障碍物的地方
                dp[0][i] = dp[0][i-1];
            }else if(obstacleGrid[0][i] == 1){
                dp[0][i] = 0;
            }else{
                dp[0][i] = 1;
            }
        }

        //遍历顺序
        for(int i = 1;i < m;i++){//外层是行
            for(int j = 1;j < n;j++){//内层是列
                if(obstacleGrid[i][j] == 0){
                    dp[i][j] = dp[i-1][j] + dp[i][j-1];
                }else{
                    dp[i][j] = 0;
                }
            }
        }
        return dp[m-1][n-1];
    }
};

改进dp数组

  1. 记录 七十四【62.不同路径】改进dp数组变成一维。那么这里也尝试一下。
class Solution {
public:
    int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
        int result;//返回值
        int m = obstacleGrid.size();//有m行
        int n = obstacleGrid[0].size();//有n列
        //定义dp[i]数组。滚动数组,每一行都更新。含义是到某一行第i+1列有dp[i][j]条路径。
        vector<int> dp(n,0);//建立数组是初始化为0;

        //dp初始化.
        for(int i = 0;i < n;i++){//初始化第一行
            if(i >0 && obstacleGrid[0][i] == 0){//没有障碍物的地方
                dp[i] = dp[i-1];
            }else if(obstacleGrid[0][i] == 1){
                dp[i] = 0;
            }else{
                dp[i] = 1;
            }
        }

        //遍历顺序
        for(int i = 1;i < m;i++){//外层是行
            for(int j = 0;j < n;j++){//内层是列
                if(j > 0 && obstacleGrid[i][j] == 0){
                    dp[j] += dp[j-1];
                }else if(obstacleGrid[i][j] == 1){
                    dp[j]= 0;
                }
            }
        }
        return dp[n-1];
    }
};

三、参考学习

63. 不同路径 II 参考学习链接

学习内容

  1. 思路和操作都是一致的,但是代码处理上可以改进。
  2. 改进初始化:因为在vector<vector> dp(m,vector (n,0));//方格初始化是0。所以一些赋值0的操作可以跳过,维持原状
for(int i = 0;i < m && obstacleGrid[i][0] == 0;i++){//初始化第一列
	dp[i][0] = 1;
}
for(int i = 0;i < n && obstacleGrid[0][i] == 0;i++){//初始化第一行
	dp[0][i] = 1;
}
  1. 递推公式:可以把else不要。
	for(int i = 1;i < m;i++){//外层是行
            for(int j = 1;j < n;j++){//内层是列
                if(obstacleGrid[i][j] == 0){
                    dp[i][j] = dp[i-1][j] + dp[i][j-1];
                }else{
                    dp[i][j] = 0;
                }
            }
        }
改成
		for (int i = 1; i < m; i++) {
            for (int j = 1; j < n; j++) {
                if (obstacleGrid[i][j] == 1) continue;
                dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
            }
        }
  1. 同理,把二、改进dp数组代码也重新改下初始化
class Solution {
public:
    int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
        int result;//返回值
        int m = obstacleGrid.size();//有m行
        int n = obstacleGrid[0].size();//有n列
        //定义dp[i]数组。滚动数组,每一行都更新。含义是到某一行第i+1列有dp[i][j]条路径。
        vector<int> dp(n,0);//建立数组是初始化为0;

        //dp初始化.
        for(int i = 0;i < n && obstacleGrid[0][i] == 0;i++){//初始化第一行
            dp[i] = 1;
        }

        //遍历顺序
        for(int i = 1;i < m;i++){//外层是行
            for(int j = 0;j < n;j++){//内层是列
                if(j > 0 && obstacleGrid[i][j] == 0){
                    dp[j] += dp[j-1];
                }else if(obstacleGrid[i][j] == 1){
                    dp[j]= 0;
                }
            }
        }
        return dp[n-1];
    }
};

总结

对比 记录 七十四【62.不同路径】
在这里插入图片描述
(欢迎指正,转载标明出处)

标签:力扣,obstacleGrid,初始化,int,II,++,63,障碍物,dp
From: https://blog.csdn.net/danaaaa/article/details/141125306

相关文章

  • IIC模拟 && E2PROM
    IIC模拟&&E2PROM IIC_eeprom.h#ifndef__IIC_EEPROM_H__#define__IIC_EEPROM_H__/*****************************************************************************************型号Byte容量页数页内字节数WORD_ADDR位数WORD_ADDR字节......
  • 力扣第五十七题——插入区间
    内容介绍给你一个 无重叠的 ,按照区间起始端点排序的区间列表 intervals,其中 intervals[i]=[starti,endi] 表示第 i 个区间的开始和结束,并且 intervals 按照 starti 升序排列。同样给定一个区间 newInterval=[start,end] 表示另一个区间的开始和结束。在......
  • LeetCode 216. 组合总和 III 回溯写法详解
    216.组合总和III216.组合总和III题目来源题目分析题目难度题目标签题目限制解题思路核心算法步骤代码实现代码解读性能分析测试用例扩展讨论优化写法其他实现总结216.组合总和III题目来源216.组合总和III题目分析题目要求找出所有相加之和为n的k......
  • 在IIS上部署ASP.NET Core Web API
    在IIS上部署ASP.NETCoreWebAPI和BlazorWasm详细教程  前言前段时间我们完成了七天.NET8操作SQLite入门到实战的开发系列教程,有不少同学留言问如何将项目发布部署到IIS上面运行。本篇文章我们就一起来讲讲在IIS上部署ASP.NETCoreWebAPI和BlazorWasm。前提条件......
  • Codeforces Round 963 (Div. 2)
    Preface有懒狗上周日的比赛拖到这周日才写博客,我不说是谁这场比赛的时候因为C数组没开两倍卡了1h最后写对拍才看出来,直接心态爆炸导致D没写完掉大分A.QuestionMarks签到#include<cstdio>#include<iostream>#include<utility>#include<vector>#include<cstring>......
  • LIinux01
    可翻页查看more空格键:代表向下翻一页Enter:代表向下翻一行/字符串:代表在当前显示内容下,向下查找字符串这个关键词:f:立刻显示当前行数和文件名q:退出moreb或[ctrl+b]代表往回翻页less空格键:向下翻一页[pagedown]:向下翻动一页``[pageup]:向上翻动一页/字符串:向下查找字符......
  • Leetcode-3132 找出与数组相加的整数II
    Leetcode-3132找出与数组相加的整数II1.题目描述2.解题思路3.代码实现1.题目描述3132找出与数组相加的整数II2.解题思路(1)排序后,注意到nums1数组比nums2数组多两个元素,可推出最小匹配元素一定在nums[0]、nums[1]、nums[2]中出现;(2)优先从nums[2]进行判......
  • CVE-2023-38633~XXE注入【春秋云境靶场渗透】
    今天我们来攻克春秋云境CTF的CVE-2023-38633#我们通过抓包来构造POC来查找/etc/passwd<?xmlversion="1.0"encoding="UTF-8"standalone="no"?><svgwidth="1000"height="1000"xmlns:xi="http://www.w3.org/2001/XInclude&......
  • linux 使用iio 通过I2C 方式采集实例
    IIO(IndustrialI/O)子系统通过I2C方式采集数据的实例。这个例子包括驱动程序和用户空间应用程序。首先,让我们创建一个简单的IIO驱动程序,它通过I2C接口与ADC(模数转换器)通信,并通过PCI总线连接到系统。1.驱动程序(my_iio_driver.c):```c#include<linux/module.h>......
  • panic: 8e85653db463fe36 state.commit 942043166 is out of range [939698375, 93970
    根据您提供的日志信息,看起来您的etcd服务遇到了一个panic错误,具体是因为state.commit的索引值942043166超出了预期的范围[939698375,939700076]。这种情况可能是由于etcd集群中的数据不一致导致的。首先,您可以尝试查看etcd集群的状态,确认所有成员是否都在正......