leetcode——网格DP系列

原文链接: https://blog.csdn.net/m0_37981481/article/details/96696615

文章目录
不同路径(基础版)
不同路径II(部分格子有障碍)
最小路径和
炸弹人游戏
地下城游戏
最大正方形
最大加号标志
最大矩形
不同路径(基础版)
【题目】
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。

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

问总共有多少条不同的路径?

例如,上图是一个7 x 3 的网格。有多少可能的路径?

【说明】m 和 n 的值均不超过 100。
【链接】https://leetcode-cn.com/problems/unique-paths
【思路】对于每个格子,到达这个格子有两种可能,要么从上面来的,要么从左边来的,所以到达该格子的可能路径数就是到达它上边那个格子的路径数加上到达它左边那个格子的路径数。

public int UniquePaths(int m, int n)
{
    var dp = new int[m, n];
    for (var i = 0; i < m; i++)
    {
        for (var j = 0; j < n; j++)
        {
            if (i == 0 || j == 0)
            {
                dp[i, j] = 1;
            }
            else
            {
                dp[i, j] = dp[i - 1, j] + dp[i, j - 1];
            }
        }
    }
    return dp[m - 1, n - 1];
}
 

不同路径II(部分格子有障碍)
leetcode题目链接:https://leetcode-cn.com/problems/unique-paths-ii/

public int UniquePathsWithObstacles(int[][] obstacleGrid)
{
    var m = obstacleGrid.Length;
    var n = obstacleGrid[0].Length;
    var dp = new int[m, n];
    dp[0, 0] = 1;
    for (var i = 0; i < m; i++)
    {
        for (var j = 0; j < n; j++)
        {
            if (obstacleGrid[i][j] == 1)
            {
                dp[i, j] = 0;
            }
            else
            {
                if (i == 0 && j == 0)
                {
                    dp[i, j] = 1;
                }
                else if (i == 0)
                {
                    dp[i, j] = dp[i, j - 1];
                }
                else if (j == 0)
                {
                    dp[i, j] = dp[i - 1, j];
                }
                else
                {
                    dp[i, j] = dp[i - 1, j] + dp[i, j - 1];
                }
            }
        }
    }
    return dp[m - 1, n - 1];
}
 

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

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

示例:

输入:
[
[1,3,1],
[1,5,1],
[4,2,1]
]
输出: 7
解释: 因为路径 1→3→1→1→1 的总和最小。

//如果可以更改输入数组的可以这么写,如果不可以更改输入数组就要重开一个二维数组存状态
public int MinPathSum(int[][] grid) {
    if (grid.Length == 0) return 0;
    int m = grid.Length;
    int n = grid[0].Length;
    
    for (int i = 0; i < m; i++)
    {
        for (int j = 0; j < n; j++)
        {
            if (i == 0 && j > 0) 
                grid[i][j] += grid[i][j-1];
            else if (j == 0 && i > 0) 
                grid[i][j] += grid[i-1][j];
            else if (i > 0 && j > 0)
                grid[i][j] += Math.Min(grid[i-1][j], grid[i][j-1]);
        }
    }
    return grid[m-1][n-1];
}

 

炸弹人游戏
想象一下炸弹人游戏,在你面前有一个二维的网格来表示地图,网格中的格子分别被以下三种符号占据:

‘W’ 表示一堵墙
‘E’ 表示一个敌人
‘0’(数字 0)表示一个空位

请你计算一个炸弹最多能炸多少敌人。
由于炸弹的威力不足以穿透墙体,炸弹只能炸到同一行和同一列没被墙体挡住的敌人。
注意:你只能把炸弹放在一个空的格子里

示例:
输入: [[“0”,“E”,“0”,“0”],[“E”,“0”,“W”,“E”],[“0”,“E”,“0”,“0”]]
输出: 3
解释: 对于如下网格

0 E 0 0
E 0 W E
0 E 0 0

假如在位置 (1,1) 放置炸弹的话,可以炸到 3 个敌人

public int MaxKilledEnemies(char[][] grid) {
    // 每个位置能炸到的人为4个方向的人的总和
    int m = grid.Length; if(m<=0) return 0;
    int n = grid[0].Length; if(n<=0) return 0;
    
    var dp = new int[m,n];
    for(int i=0; i         // 计算当前行相邻两个墙壁之间人的个数
        int s = -1;
        int j = s+1;
        while(j             int count = 0;
            while(j                 count += (grid[i][j]=='E'?1:0);
                j++;
            }
            for(int k=s+1; k                 if(grid[i][k]=='0'){
                    dp[i,k] += count;
                }
            }
            s = j;
            j = s+1;
        }
    }
    for(int i=0; i         int s = -1;
        int j = s+1;
        while(j             int count = 0;
            while(j                 count += (grid[j][i]=='E'?1:0);
                j++;
            }
            for(int k=s+1; k                 if(grid[k][i]=='0'){
                    dp[k,i] += count;
                }
            }
            s = j;
            j = s+1;
        }
    }
    int ans = -1;
    foreach(var val in dp){
        ans = Math.Max(ans, val);
    }
    return ans;
}

地下城游戏

一些恶魔抓住了公主(P)并将她关在了地下城的右下角。地下城是由 M x N 个房间组成的二维网格。我们英勇的骑士(K)最初被安置在左上角的房间里,他必须穿过地下城并通过对抗恶魔来拯救公主。

骑士的初始健康点数为一个正整数。如果他的健康点数在某一时刻降至 0 或以下,他会立即死亡。

有些房间由恶魔守卫,因此骑士在进入这些房间时会失去健康点数(若房间里的值为负整数,则表示骑士将损失健康点数);其他房间要么是空的(房间里的值为 0),要么包含增加骑士健康点数的魔法球(若房间里的值为正整数,则表示骑士将增加健康点数)。

为了尽快到达公主,骑士决定每次只向右或向下移动一步。

编写一个函数来计算确保骑士能够拯救到公主所需的最低初始健康点数。

例如,考虑到如下布局的地下城,如果骑士遵循最佳路径 右 -> 右 -> 下 -> 下,则骑士的初始健康点数至少为 7。

-2 (K) -3 3
-5 -10 1
10 30 -5 §

说明:

骑士的健康点数没有上限。

任何房间都可能对骑士的健康点数造成威胁,也可能增加骑士的健康点数,包括骑士进入的左上角房间以及公主被监禁的右下角房间。

链接:https://leetcode-cn.com/problems/dungeon-game

public int CalculateMinimumHP(int[][] dungeon) {
    int row=dungeon.Length,col=dungeon[0].Length;
    int[,] dp=new int[row,col];
    for(int r=row-1;r>-1;r--)
        for(int c=col-1;c>-1;c--) {
           if(r==row-1&&c==col-1) {
               dp[row-1,col-1]=dungeon[row-1][col-1]<0?1-dungeon[row-1][col-1]:1; continue;
           }
           if(r+1                if(dungeon[r][c]>=0) {
                   if(1+dungeon[r][c]>=dp[r+1,c]) dp[r,c]=1;
                   else dp[r,c]=dp[r+1,c]-dungeon[r][c];
               }
               else dp[r,c]=dp[r+1,c]-dungeon[r][c];
           }
           if(c+1                int value;
               if(dungeon[r][c]>=0) {
                   if(1+dungeon[r][c]>=dp[r,c+1]) value=1;
                   else value=dp[r,c+1]-dungeon[r][c];
               }
               else value=dp[r,c+1]-dungeon[r][c]; 
               if(r+1dp[r,c]) ;
               else dp[r,c]=value;
           }
        }
    return dp[0,0];
}
 

最大正方形
在一个由 0 和 1 组成的二维矩阵内,找到只包含 1 的最大正方形,并返回其面积。

示例:

输入:

1 0 1 0 0
1 0 1 1 1
1 1 1 1 1
1 0 0 1 0

输出: 4

链接:https://leetcode-cn.com/problems/maximal-square

//注意1*1的测例,注意matrix是char数组,注意普通情况下矩阵内部的1的处理
public int MaximalSquare(char[][] matrix) {
    var m = matrix.Length;
    if(m==0) return 0;
    var n = matrix[0].Length;
    var dp = new int[m,n];
    var max = 0;
    for(var i=0;i         for(var j=0;j             if(i<1||j<1){
                dp[i,j] = matrix[i][j]=='1'?1:0;
            }
            else if(matrix[i][j]=='1'){
                dp[i,j]=1;
                if(matrix[i-1][j-1]=='1'){
                    dp[i,j]=Math.Min(dp[i-1,j-1],Math.Min(dp[i-1,j],dp[i,j-1]))+1;
                }
            }
            max = Math.Max(dp[i,j]*dp[i,j], max);
        }
    }
    return max;
}
 

最大加号标志
在一个大小在 (0, 0) 到 (N-1, N-1) 的2D网格 grid 中,除了在 mines 中给出的单元为 0,其他每个单元都是 1。网格中包含 1 的最大的轴对齐加号标志是多少阶?返回加号标志的阶数。如果未找到加号标志,则返回 0。

一个 k" 阶由 1 组成的“轴对称”加号标志具有中心网格 grid[x][y] = 1 ,以及4个从中心向上、向下、向左、向右延伸,长度为 k-1,由 1 组成的臂。下面给出 k" 阶“轴对称”加号标志的示例。注意,只有加号标志的所有网格要求为 1,别的网格可能为 0 也可能为 1。

k 阶轴对称加号标志示例:

阶 1:
000
010
000

阶 2:
00000
00100
01110
00100
00000

阶 3:
0000000
0001000
0001000
0111110
0001000
0001000
0000000

示例 1:

输入: N = 5, mines = [[4, 2]]
输出: 2
解释:

11111
11111
11111
11111
11011

在上面的网格中,最大加号标志的阶只能是2。一个标志已在图中标出。

示例 2:

输入: N = 2, mines = []
输出: 1
解释:

11
11

没有 2 阶加号标志,有 1 阶加号标志。

示例 3:

输入: N = 1, mines = [[0, 0]]
输出: 0
解释:

0

没有加号标志,返回 0 。

提示:

整数N 的范围: [1, 500].
mines 的最大长度为 5000.
mines[i] 是长度为2的由2个 [0, N-1] 中的数组成.
(另外,使用 C, C++, 或者 C# 编程将以稍小的时间限制进行​​判断.)

链接:https://leetcode-cn.com/problems/largest-plus-sign

public int OrderOfLargestPlusSign(int N, int[][] mines) {
    var grid = new int[N,N];

    for (int i = 0; i < N; i++) {
        for (var j = 0; j < N; j++) {
            grid[i,j] = N;
        }
    }

    foreach (int[] m in mines) {
        grid[m[0],m[1]] = 0;
    }

    for (int i = 0; i < N; i++) {
        for (int j = 0, k = N - 1, l = 0, r = 0, u = 0, d = 0; j < N; j++, k--) {
            grid[i,j] = Math.Min(grid[i,j], l = (grid[i,j] == 0 ? 0 : l + 1));  // left direction
            grid[i,k] = Math.Min(grid[i,k], r = (grid[i,k] == 0 ? 0 : r + 1));  // right direction
            grid[j,i] = Math.Min(grid[j,i], u = (grid[j,i] == 0 ? 0 : u + 1));  // up direction
            grid[k,i] = Math.Min(grid[k,i], d = (grid[k,i] == 0 ? 0 : d + 1));  // down direction
        }
    }

    int res = 0;

    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            res = Math.Max(res, grid[i,j]);
        }
    }

    return res;
}
 

最大矩形
给定一个仅包含 0 和 1 的二维二进制矩阵,找出只包含 1 的最大矩形,并返回其面积。

示例:

输入:
[
[“1”,“0”,“1”,“0”,“0”],
[“1”,“0”,“1”,“1”,“1”],
[“1”,“1”,“1”,“1”,“1”],
[“1”,“0”,“0”,“1”,“0”]
]
输出: 6

链接:https://leetcode-cn.com/problems/maximal-rectangle

public int MaximalRectangle(char[][] matrix) {
    if (matrix.Length == 0) return 0;
    int maxarea = 0;
    var dp = new int[matrix.Length,matrix[0].Length];

    for(int i = 0; i < matrix.Length; i++){
        for(int j = 0; j < matrix[0].Length; j++){
            if (matrix[i][j] == '1'){

                // compute the maximum width and update dp with it
                dp[i,j] = j == 0? 1 : dp[i,j-1] + 1;

                int width = dp[i,j];

                // compute the maximum area rectangle with a lower right corner at [i, j]
                for(int k = i; k >= 0; k--){
                    width = Math.Min(width, dp[k,j]);
                    maxarea = Math.Max(maxarea, width * (i - k + 1));
                }
            }
        }
    } 
    return maxarea;
}
 


 

你可能感兴趣的:(leetcode——网格DP系列)