leetcode - [动态规划] -最大加号标志(764)

本文介绍了LeetCode中的一道题目——寻找2D网格中最大阶的轴对称加号。文章详细阐述了问题描述、解题思路,包括暴力法和动态规划优化的解决方案,并给出了相应的代码实现。
摘要由CSDN通过智能技术生成

1、问题描述

在一个大小在(0,0)到(N-1,N-1)的2D网格grid中,除了mines给出的单元格为0,其他单元格都为1。网格中包含1的最大轴对称加号的阶是多少,返回最大轴对称加号的阶。如果不存在轴对称加号,则返回0.
一个k阶轴由1组成的轴对称加号指的是具有中心网格grid[x][y],以及从中心向上、向下、向左、向右延伸,长度为k-1,由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 阶加号标志。

2、解题思路

思路1暴力法。我们可以每个为“1”的单元格为中心,计算其向上、向下、向左、向右四个方向的臂长(即该单元格向这个四个方向的连续“1”的个数),这个臂长中的最小值即为以该单元格为中心的轴对称加号的阶。
这种方法的时间复杂度为 O ( N 3 ) O(N^3) O(N3),空间复杂度为 O ( 1 ) O(1) O(1).

思路2动态规划 - 优化的暴力法。其实,对于值为每个单1的单元格,其向左、向右、向上、向下四个方向的连续“1”的个数是可以提前计算出来的。
比如,对于某一行 [ 1 , 0 , 1 , 1 , 1 , 0 , 1 , 1 ] [1,0,1,1,1,0,1,1] [1,0,1,1,1,0,1,1],每个位置向左方向连续“1”的个数为 [ 1 , 0 , 1 , 2 , 3 , 0 , 1 , 2 ] [1,0,1,2,3,0,1,2] [1,0,1,2,3,0,1,2]
具体的计算方法如下:

/*注意:
下列算法row[j]表示某一行的第j列元素;
dp[j]表示从左边界开始到row[j]连续1的个数。
*/
#for j = 0 to len:
	*if(row[j] == 0):
		#dp[j] = 0;
	*else if(row[j] == 1):
		#if(j > 0 && row[j-1] == 1):
			*dp[j] = dp[j-1]+1;
		#else:
			*dp[j] = 1;
			

只要使用类似上述的方法求出每个为“1"的单元格向上、向下、向左、向右四个方向的连续1的个数,并存储在up、down、left、right中,则以该单元格为中心的轴对称加号的阶为min{left,right,up,down};

时间复杂度: O ( N 2 ) O(N^2) O(N2).
空间复杂度: O ( N 2 ) O(N^2) O(N2).

3、代码实现

/*基本思想:
对于每个网格grid[r][c],分别计算从gird[r][c]开始, left、right、up、down四个方向上1的连续个数,
并把它们存储下来,则以grid[r][c]为中心的轴对称加号标志的最大阶
dp[r][c] = min{left[r][c],right[r][c],up[r][c],down[r][c]} 
计算left[r][c]的规则如下:
(1) 如果grid[r][c] 等于0,则left[r][c]为0;
(2) 如果grid[r][c]等于1并且它的前一个也为1,则left[r][c] = left[r][c-1] + 1, 否则left[r][c] = 1;
假设gird有一行为0111011,则left为0123012*/
class Solution {
public:
    int orderOfLargestPlusSign(int N, vector<vector<int>>& mines) {
        vector<vector<int>> grid(N,vector<int>(N,1));
        for(int i = 0; i < mines.size(); i++){
            grid[mines[i][0]][mines[i][1]] = 0;
        }
        vector<vector<int>> left(N,vector<int>(N,0));
        vector<vector<int>> right(N, vector<int>(N,0));
        vector<vector<int>> up(N,vector<int>(N,0));
        vector<vector<int>> down(N, vector<int>(N,0));
        for(int i = 0; i < N; i++){
            for(int j = 0; j < N; j++){
                if(grid[i][j] == 0){
                    left[i][j] = 0;
                }
                else{
                    if(j > 0 && grid[i][j-1] == 1){
                        left[i][j] = left[i][j-1] + 1;
                    }
                    else{
                        left[i][j] = 1;
                    }
                }

                int k = N-1-j;
                if(grid[i][k] == 0){
                    right[i][k] = 0;
                }
                else{
                    if(k < N-1 && grid[i][k+1] == 1){
                        right[i][k] = right[i][k+1] + 1;
                    }
                    else{
                        right[i][k] = 1;
                    }
                }
                
                if(grid[j][i] == 0){
                    up[j][i] = 0;
                }
                else{
                    if(j > 0 && grid[j-1][i] == 1){
                        up[j][i] = up[j-1][i] + 1;
                    }
                    else{
                        up[j][i] = 1;
                    }
                }

                int p = N-1-j;
                if(grid[p][i] == 0){
                    down[p][i] = 0;
                }
                else{
                    if(p < N-1 && grid[p+1][i] == 1){
                        down[p][i] = down[p+1][i] + 1;
                    }
                    else{
                        down[p][i] = 1;
                    }
                }
            }
        }
        int maxlen = 0;
        for(int r = 0; r < N; r++){
            for(int c = 0; c < N; c++){
                // cout<<"r="<<r<<"c="<<c<<":"<<"("<<left[r][c]<<","<<right[r][c]<<","<<up[r][c]<<","<<down[r][c]<<")"<<endl;
                int len = min(min(left[r][c],right[r][c]),min(up[r][c],down[r][c]));
                if(len > maxlen){
                    maxlen = len;
                }
            }
        }
        return maxlen;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Albert_YuHan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值