最大矩形, 统计全1子矩阵

美团笔试题-最大矩形

暴力直接解决, 输入处理较为麻烦。
LeetCode 85 一样。

import java.util.*;
public class Main {
    static int solve(int[][] arr, int n, int m) {
        int area = 0;
        for(int a = 0; a < n; a++){
            for(int b = 0; b < m; b++) {
                for(int c = 0; c <= a; c++){
                    for(int d = 0; d <= b; d++) {
                        int t = 0;
                        for(int i=c; i <= a; i++)
                            for(int j=d; j <= b; j++)
                                if(arr[i][j] == 1) t++;
                        if(t == (a-c+1)*(b-d+1))
                            area = Math.max(area, t);
                    }
                }
            }
        }
        return area;
    }
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        if(sc.hasNext()) sc.nextLine();
        List<String> list = new ArrayList<>();
        while(true){
            char[] s = sc.nextLine().toCharArray();
            StringBuilder sb = new StringBuilder();
            for(int i=0; i < s.length;i++)
                if(s[i] == '0' || s[i] == '1')
                    sb.append(s[i]);
            if(sb.length() == 0) break;
            list.add(sb.toString());
            if(s[s.length-1] != ',') break;
        }
        if(sc.hasNext()) sc.nextLine();
        int n = list.size(), m = list.get(0).length();
        int[][] a = new int[n][m];
        for(int i=0; i < n; i++)
            for(int j=0; j < m; j++)
                a[i][j] = list.get(i).charAt(j) == '1' ? 1 : 0;
        int area = solve(a, n, m);
 
        System.out.println(area);
    }
}

Leetcode 1504. 统计全1子矩阵

N, M <= 150
使用二维前缀和优化,时间复杂度:O(N*M*N*M)

class Solution {
    public int numSubmat(int[][] mat) {
        int n = mat.length, m = mat[0].length;
        int[][] f = new int[n+1][m+1];
        for(int i=1; i <= n; i++)
            for(int j=1; j <= m; j++) {
                f[i][j] = f[i-1][j]+f[i][j-1]-f[i-1][j-1];
                if(mat[i-1][j-1] == 1) f[i][j]++;
            }
        int count = 0;
        for(int a = 1; a <= n; a++) {
            for(int b=1; b <= m; b++) {
                for(int c=1; c <= a; c++) {
                    for(int d=1; d <= b; d++) {
                        int t = f[a][b] - f[a][d-1] - f[c-1][b] + f[c-1][d-1];
                        if(t == (a-c+1)*(b-d+1))
                            count++;
                    }
                }
            }
        }
        return count;
    }
}

优化版思路:

  1. 求出每行的前缀和
  2. 遍历所有可能子矩阵的左列和右列, 根据前缀和和以计算出每一行左列到右列间1的数量。
  3. 遍历行, 连续x行每行左列到右列间全为1,则有 x(x+1)/2 种矩阵。
    时间复杂度:O(N*M*M)
class Solution {
    public int numSubmat(int[][] mat) {
        int n = mat.length, m = mat[0].length;
        int[][] f = new int[n][m+1]; //每行的前缀和
        for(int i=0; i < n; i++) {
            for(int j=1; j <= m; j++)
                f[i][j] = f[i][j-1] + mat[i][j-1];
        }
        int count = 0;
        for(int a = 0; a < m; a++) { // 矩阵左列
            for(int b=a; b < m; b++) { // 矩阵右列
                int cnt = 0;
                for(int i=0; i < n; i++) {
                    int sum = f[i][b+1] - f[i][a];
                    if(sum == b-a+1)
                        cnt++;
                    else {
                        count += cnt*(cnt+1) / 2;
                        cnt = 0;
                    }
                }
                if(cnt != 0) count += cnt*(cnt+1) / 2;
            }
        }
        return count;
    }
}
原文地址:https://www.cnblogs.com/lixyuan/p/13288574.html