算法进修Day-32

算法进修Day-32

63. 不同路径II

难度:中等

题目要求:

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

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

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

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

示例1

输入:obstacleGrid = \[0,0,0,0,1,0,0,0,0]

输出:2

示例2

输入:obstacleGrid = \[0,1,0,0]

输出:1

题解

由于每次只能向下或者向右移动,因此对于网格中的每个位置,到达该位置的路径数目需要通过相邻元素的路径数目计算得到。可以使用动态规划计算路径数目。

如果左上角 o b s t a c l e G r i d 0 0 obstacleGrid00 obstacleGrid00 或右上角 o b s t a c l e G r i d m − 1 n − 1 obstacleGridm-1n-1 obstacleGridm−1n−11时直接返回0

动态规划步骤如下

  • 创建 m ∗ n m*n m∗n 的二维数组 d p dp dp
  • 当 i = 0 , j = 0 i=0,j=0 i=0,j=0,路径 ( 0 , 0 ) (0,0) (0,0) 上只有一个位置,路径数目为1,所以边界情况为 d p 0 0 = 1 dp00=1 dp00=1
  • 当 i > 0 , j > 0 i>0,j>0 i>0,j>0,需要考虑如下方面
    • 当 i = 0 , j > 0 i=0,j>0 i=0,j>0,只能从 ( i , j − 1 ) (i,j-1) (i,j−1) 向右移动到 ( i , j ) (i,j) (i,j),如果 o b s t a c l e G r i d i j = 0 obstacleGridij=0 obstacleGridij=0 则 d p i j = d p i j − 1 dpij=dpij-1 dpij=dpij−1,如果 o b s t a c l e G r i d i j = 1 obstacleGridij=1 obstacleGridij=1 则 d p i j = 0 dpij=0 dpij=0
    • 当 i > 0 , j = 0 i>0,j=0 i>0,j=0,只能从 ( i − 1 , j ) (i-1,j) (i−1,j) 向下移动到 ( i , j ) (i,j) (i,j),如果 o b s t a c l e G r i d i j = 0 obstacleGridij=0 obstacleGridij=0 则 d p i j = d p i − 1 j dpij=dpi-1j dpij=dpi−1j,如果 o b s t a c l e G r i d i j = 1 obstacleGridij=1 obstacleGridij=1 则 d p i j = 0 dpij=0 dpij=0
    • 当 i > 0 , j > 0 i>0,j>0 i>0,j>0,可以从 ( i − 1 , j ) (i-1,j) (i−1,j) 向下移动到 ( i , j ) (i,j) (i,j) 或从 ( i , j − 1 ) (i,j-1) (i,j−1) 向右移动到 ( i , j ) (i,j) (i,j),如果 o b s t a c l e G r i d i j = 0 obstacleGridij=0 obstacleGridij=0 则 d p i j = d p i − 1 j + d p i j − 1 dpij=dpi-1j+dpij-1 dpij=dpi−1j+dpij−1,如果 o b s t a c l e G r i d i j = 1 obstacleGridij=1 obstacleGridij=1 则 d p i j = 0 dpij=0 dpij=0

所以,当 i > 0 i>0 i>0 或 j > 0 j>0 j>0,动态规划转移方程如下:
d p i j = { 0 , obstacleGridij=1 d p i j − 1 , obstacleGridij=0 & i=0 & j>0 d p i − 1 j , obstacleGridij=0 & i>0 & j=0 d p i − 1 j + d p i j − 1 , obstacleGridij=0 & i>0 & j>0 dpij=\begin{cases} 0, & \text{obstacleGridij=1}\\dpij-1,&\text{obstacleGridij=0 \& i=0 \& j>0}\\dpi-1j,&\text{obstacleGridij=0 \& i>0 \& j=0}\\dpi-1j+dpij-1, &\text{obstacleGridij=0 \& i>0 \& j>0} \end{cases} dpij=⎩ ⎨ ⎧0,dpij−1,dpi−1j,dpi−1j+dpij−1,obstacleGridij=1obstacleGridij=0 & i=0 & j>0obstacleGridij=0 & i>0 & j=0obstacleGridij=0 & i>0 & j>0

根据动态规划的状态转移方程,计算 d p i j dpij dpij 的顺序可以是一下两种

  • 从小到大遍历每个 i i i,对于每个 i i i 从小到大遍历每个 j j j。该顺序为按行遍历
  • 从小到大遍历每个 j j j,对于每个 j j j 从小大大便利每个 i i i。该顺序为按列遍历

计算得到 d p m − 1 n − 1 dpm-1n-1 dpm−1n−1 即为从左上角到右上角的路径的最小值的和

想法代码

Csharp 复制代码
class Solution
{
    public static void Main(String[] args)
    {
        int[][] obstacleGrid =
        {
            new[]{0,0,0,0},
            new[]{0,1,0,0},
            new[]{0,0,0,0},
            new[]{0,0,1,0},
            new[]{0,0,0,0},
        };
        Solution solution = new Solution();
        int res = solution.UniquePathsWithObstacles(obstacleGrid);
        Console.WriteLine(res);
    }

    public int UniquePathsWithObstacles(int[][] obstacleGrid)
    {
        int m = obstacleGrid.Length, n = obstacleGrid[0].Length;
        if (obstacleGrid[0][0] == 1 || obstacleGrid[m - 1][n - 1] == 1)
        {
            return 0;
        }
        int[][] dp = new int[m][];
        for (int i = 0; i < m; i++)
        {
            dp[i] = new int[n];
        }
        dp[0][0] = 1;
        for (int j = 1; j < n && obstacleGrid[0][j] == 0; j++)
        {
            dp[0][j] = 1;
        }
        for (int i = 1; i < m && obstacleGrid[i][0] == 0; i++)
        {
            dp[i][0] = 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];
                }
            }
        }
        return dp[m - 1][n - 1];
    }
}

64. 最小路径和

难度:中等

题目要求:

给定一个包含非负整数的 _m_ x _n_ 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。

说明:每次只能向下或者向右移动一步。

示例1

输入:grid = \[1,3,1,1,5,1,4,2,1]

输出:7

示例2

输入:grid = \[1,2,3,4,5,6]

输出:12

题解

由于每次只能向下或者向右移动,因此对于网格中的每个位置,到达该位置的路径数目需要通过相邻元素的路径数目计算得到。可以使用动态规划计算路径数目。

动态规划步骤如下

  • 创建 m ∗ n m*n m∗n 的二维数组 d p dp dp
  • 当 i = 0 , j = 0 i=0,j=0 i=0,j=0,路径 ( 0 , 0 ) (0,0) (0,0) 上只有一个位置,最小路径和为 g r i d 0 0 grid00 grid00,所以边界情况为 d p 0 0 = g r i d 0 0 dp00=grid00 dp00=grid00
  • 当 i > 0 , j > 0 i>0,j>0 i>0,j>0,需要考虑如下方面
    • 当 i = 0 , j > 0 i=0,j>0 i=0,j>0,只能从 ( i , j − 1 ) (i,j-1) (i,j−1) 向右移动到 ( i , j ) (i,j) (i,j),如果 d p i j = 0 dpij=0 dpij=0 则 d p i j = g r i d i j + d p i j − 1 dpij=gridij+dpij-1 dpij=gridij+dpij−1
    • 当 i > 0 , j = 0 i>0,j=0 i>0,j=0,只能从 ( i − 1 , j ) (i-1,j) (i−1,j) 向下移动到 ( i , j ) (i,j) (i,j),如果 d p i j = 0 dpij=0 dpij=0 则 d p i j = g r i d i j + d p i − 1 j dpij=gridij+dpi-1j dpij=gridij+dpi−1j
    • 当 i > 0 , j > 0 i>0,j>0 i>0,j>0,可以从 ( i − 1 , j ) (i-1,j) (i−1,j) 向下移动到 ( i , j ) (i,j) (i,j) 或从 ( i , j − 1 ) (i,j-1) (i,j−1) 向右移动到 ( i , j ) (i,j) (i,j),到达 ( i , j ) (i,j) (i,j) 最小路径和为两种情况的最小值,因此 d p i j = m i n ( d p i − 1 j , d p i j − 1 + d p i j − 1 ) + g r i d i j dpij=min(dpi-1j,dpij-1+dpij-1)+gridij dpij=min(dpi−1j,dpij−1+dpij−1)+gridij

所以,当 i > 0 i>0 i>0 或 j > 0 j>0 j>0,动态规划转移方程如下:
d p i j = { d p i j − 1 + g r i d i j , i=0 & j>0 d p i − 1 j + g r i d i j , i>0 & j=0 m i n ( d p i − 1 j , d p i j − 1 ) + g r i d i j , i>0 & j>0 dpij=\begin{cases} dpij-1+gridij, & \text{i=0 \& j>0}\\dpi-1j+gridij,&\text{i>0 \& j=0}\\min(dpi-1j,dpij-1)+gridij,&\text{i>0 \& j>0} \end{cases} dpij=⎩ ⎨ ⎧dpij−1+gridij,dpi−1j+gridij,min(dpi−1j,dpij−1)+gridij,i=0 & j>0i>0 & j=0i>0 & j>0

根据动态规划的状态转移方程,计算 d p i j dpij dpij 的顺序可以是一下两种

  • 从小到大遍历每个 i i i,对于每个 i i i 从小到大遍历每个 j j j。该顺序为按行遍历
  • 从小到大遍历每个 j j j,对于每个 j j j 从小大大便利每个 i i i。该顺序为按列遍历

计算得到 d p m − 1 n − 1 dpm-1n-1 dpm−1n−1 即为从左上角到右上角的最小路径和

题解

Csharp 复制代码
class Solution
{
    public static void Main(String[] args)
    {
        int[][] grid =
        {
            new[] { 1, 3, 1 },
            new[] { 1, 5, 1 },
            new[] { 4, 2, 1 }
        };
        Solution solution = new Solution();
        int res = solution.MinPathSum(grid);
        Console.WriteLine(res);
    }

    public int MinPathSum(int[][] grid)
    {
        int m = grid.Length, n = grid[0].Length;
        int[][] dp = new int[m][];
        for (int i = 0; i < m; i++)
        {
            dp[i] = new int[n];
        }
        dp[0][0] = grid[0][0];
        for (int j = 1; j < n; j++)
        {
            dp[0][j] = dp[0][j - 1] + grid[0][j];
        }
        for (int i = 1; i < m; i++)
        {
            dp[i][0] = dp[i - 1][0] + grid[i][0];
        }
        for (int i = 1; i < m; i++)
        {
            for (int j = 1; j < n; j++)
            {
                dp[i][j] = Math.Min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j];
            }
        }
        return dp[m - 1][n - 1];
    }
}
相关推荐
YUS云生42 分钟前
大模型学习·第41天:LangChain进阶——提示词模板与Chain链式调用
学习·langchain·c#
冻柠檬飞冰走茶1 小时前
PTA基础编程题目集 7-27 冒泡法排序(C语言实现)
c语言·开发语言·数据结构·算法
SunnyDays10112 小时前
C# 加密和解密 PDF:设置密码、AES 加密及操作权限
pdf·c#·加密 pdf·解除 pdf 密码·pdf 权限设置·pdf 文档安全
大鱼>3 小时前
因子挖掘+回测+RL交易:量化金融完整系统
人工智能·深度学习·算法·金融
布鲁飞丝4 小时前
对 .NET线程 异常退出引发程序崩溃的反思
数据库·c#·.net
SamChan904 小时前
WebSocket实现PDF翻译进度实时推送:Go后端+React前端的完整方案
前端·websocket·pdf·c#·react·机器翻译
c238564 小时前
《枚举算法 “翻译官”:用 enum class 给 “游游的礼盒” 算分》
c语言·c++·算法
吃好睡好便好4 小时前
MATLAB中图像的对数变换
图像处理·学习·算法·计算机视觉·matlab
noipp4 小时前
推荐题目:洛谷 P5843 [SCOI2012] Blinker 的噩梦
c语言·数据结构·c++·算法·游戏·洛谷·luogu
极客BIM工作室4 小时前
OpenCascade 倒角(Chamfer)算法完整逻辑解析
算法