562. 矩阵中最长的连续1线段

562. 矩阵中最长的连续1线段

给定一个01矩阵 mat,找到矩阵中最长的连续1线段。这条线段可以是水平的、垂直的、对角线的或者反对角线的。

示例:

输入:
[[0,1,1,0],
 [0,1,1,0],
 [0,0,0,1]]
输出: 3

提示: 给定矩阵中的元素数量不会超过 10,000。

解法一:标准 DP

思想

状态表示

  • f ( 0 , i , j ) f(0,i,j) f(0,i,j) 表示以 ( i , j ) (i,j) (i,j) 点为结尾的 水平 连续 1 线段的长度
  • f ( 1 , i , j ) f(1,i,j) f(1,i,j) 表示以 ( i , j ) (i,j) (i,j) 点为结尾的 垂直 连续 1 线段的长度
  • f ( 2 , i , j ) f(2,i,j) f(2,i,j) 表示以 ( i , j ) (i,j) (i,j) 点为结尾的 对角 连续 1 线段的长度
  • f ( 3 , i , j ) f(3,i,j) f(3,i,j) 表示以 ( i , j ) (i,j) (i,j) 点为结尾的 反对角 连续 1 线段的长度

此处 i , j i,j i,j 1 1 1 开始,题中所给矩阵的下标从 0 0 0 开始,所以 f f f 中的 i , j i,j i,j 对应与 m a t mat mat i − 1 , j − 1 i-1,j-1 i1,j1

状态转移

  • ( i , j ) (i,j) (i,j) 点结尾的 水平 连续 1 线段的长度与以 ( i , j − 1 ) (i, j - 1) (i,j1) 点结尾的 水平 连续 1 线段的长度有关

    f ( 0 , i , j , 0 ) f(0,i,j,0) f(0,i,j,0) f ( 0 , i , j − 1 ) f(0,i,j - 1) f(0,i,j1) 转移

  • ( i , j ) (i,j) (i,j) 点结尾的 垂直 连续 1 线段的长度与以 ( i − 1 , j ) (i - 1, j) (i1,j) 点结尾的 垂直 连续 1 线段的长度有关

    f ( 1 , i , j ) f(1,i,j) f(1,i,j) f ( 1 , i − 1 , j ) f(1,i - 1 ,j) f(1,i1,j) 转移

  • ( i , j ) (i,j) (i,j) 点结尾的 对角 连续 1 线段的长度与以 ( i − 1 , j − 1 ) (i - 1, j-1) (i1,j1) 点结尾的 对角 连续 1 线段的长度有关

    f ( 2 , i , j ) f(2,i,j) f(2,i,j) f ( 2 , i − 1 , j − 1 ) f(2,i - 1,j-1) f(2,i1,j1) 转移

  • ( i , j ) (i,j) (i,j) 点结尾的 反对角 连续 1 线段的长度与以 ( i − 1 , j + 1 ) (i - 1, j + 1) (i1,j+1) 点结尾的 反对角 连续 1 线段的长度有关

    f ( 3 , i , j ) f(3,i,j) f(3,i,j) f ( 3 , i − 1 , j + 1 ) f(3,i - 1,j + 1) f(3,i1,j+1) 转移

状态计算

  • ( i , j ) (i,j) (i,j) 点为 1 时,连续 1 的长度增长 1
  • ( i , j ) (i,j) (i,j) 点为 0 0 0 时,连续 1 中断,所以连续 1 为 0

复杂度

时间复杂度: O ( N M ) O(NM) O(NM) N N N m a t mat mat 行数, M M M m a t mat mat 列数

空间复杂度: O ( N M ) O(NM) O(NM)

代码

class Solution {
    public int longestLine(int[][] mat) {        
        int n = mat.length, m = mat[0].length;
        int[][][] f = new int[4][n + 2][m + 2]; 
        int res = 0;
        for (int i = 1; i <= n; i++) {            
            for (int j = 1; j <= m; j++) {
                boolean flag = mat[i - 1][j - 1] == 1;
                f[0][i][j] = flag ? f[0][i + 0][j - 1] + 1 : 0;
                f[1][i][j] = flag ? f[1][i - 1][j + 0] + 1 : 0;
                f[2][i][j] = flag ? f[2][i - 1][j - 1] + 1 : 0;
                f[3][i][j] = flag ? f[3][i - 1][j + 1] + 1 : 0;
                for (int k = 0; k < 4; k++) {                    
                    res = Math.max(res, f[k][i][j]);    
                }
            }          	
        }
        return res;
    }
}

解法二:滚动数组优化

思想

由解法一可得所有状态递推公式

f[0][i][j] = f[0][i + 0][j - 1] + 1;
f[1][i][j] = f[1][i - 1][j + 0] + 1;
f[2][i][j] = f[2][i - 1][j - 1] + 1;
f[3][i][j] = f[3][i - 1][j + 1] + 1;

k = 0 k = 0 k=0 外,对于 f[i] 来说只依赖于 f[i - 1] ,所以可以用两组数组滚动更新。

复杂度

时间复杂度: O ( N M ) O(NM) O(NM)

空间复杂度: O ( M ) O(M) O(M)

代码

class Solution {
    public int longestLine(int[][] mat) {        
        int n = mat.length, m = mat[0].length;
        int[][] f = new int[4][m + 2]; 
        int res = 0;
        for (int i = 1; i <= n; i++) { 
            int[][] g = new int[4][m + 2];            
            for (int j = 1; j <= m; j++) {
                boolean flag = mat[i - 1][j - 1] == 1;
                g[0][j] = flag ? g[0][j - 1] + 1 : 0;
                g[1][j] = flag ? f[1][j + 0] + 1 : 0;
                g[2][j] = flag ? f[2][j - 1] + 1 : 0;
                g[3][j] = flag ? f[3][j + 1] + 1 : 0;
                for (int k = 0; k < 4; k++) {                    
                    res = Math.max(res, g[k][j]); 
                }
            }   
            for (int k = 0; k < 4; k++) {
                f[k] = g[k];
            }
        }
        return res;
    }
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值