美团笔试题-最大矩形
暴力直接解决, 输入处理较为麻烦。
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的数量。
- 遍历行, 连续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;
}
}