给定一个由 '0' 和 '1' 组成的2维矩阵,返回该矩阵中最大的由 '1' 组成的正方形的面积。输入的矩阵是字符形式而非数字形式。
数据范围:矩阵的长宽满足 ,矩阵中的元素属于 {'1','0'}
进阶:空间复杂度 , 时间复杂度
[[1,0,1,0,0],[1,0,1,1,1],[1,1,1,1,1],[1,0,0,1,0]]
4
[[1,0,0],[0,0,0],[0,0,0]]
1
import java.util.*; //https://www.nowcoder.com/practice/0058c4092cec44c2975e38223f10470e?tpId=117&&tqId=37832&rp=1&ru=/activity/oj&qru=/ta/job-code-high/question-ranking public class Solution { /** * 最大正方形 * @param matrix char字符型二维数组 * @return int整型 */ public int solve (char[][] matrix) { //二维矩阵的宽和高 int height = matrix.length; int width = matrix[0].length; int[][] dp = new int[height + 1][width + 1]; int maxSide = 0;//最大正方形的宽 for (int i = 1; i <= height; i++) { for (int j = 1; j <= width; j++) { if (matrix[i - 1][j - 1] == '1') { //递推公式 dp[i][j] = Math.min(dp[i - 1][j], Math.min(dp[i - 1][j - 1], dp[i][j - 1])) + 1; //记录最大的边长 maxSide = Math.max(maxSide, dp[i][j]); } } } //返回正方形的面积 return maxSide * maxSide; } }
import java.util.*; public class Solution { /** * 最大正方形 * @param matrix char字符型二维数组 * @return int整型 */ public int solve (char[][] matrix) { // write code here int [][]dp = new int[matrix.length][matrix[0].length]; int bc = 0; dp[0][0]=0; for(int i=0;i<dp.length;i++){ dp[i][0]=matrix[i][0]-'0'; } for(int j=0;j<dp[0].length;j++){ dp[0][j]=matrix[0][j]-'0'; } for(int i=1;i<dp.length;i++){ for(int j=1;j<dp[0].length;j++){ if(matrix[i][j]=='0'){ dp[i][j]=0; }else{ int up = dp[i-1][j]; int left = dp[i][j-1]; int ul = dp[i-1][j-1]; if(up==left && up==ul){ dp[i][j]=up+1; }else{ int m = Math.min(up,Math.min(left,ul)); dp[i][j]=m+1; } } } } for(int i=0;i<dp.length;i++){ for(int j=0;j<dp[0].length;j++){ bc = Math.max(bc,dp[i][j]); } } int area = bc*bc; return area; } }前排提示:这道题有个很坑的地方,java输入的matrix是字符型。自测的时候算出来面积两千多,一直不知道啥问题,一看函数参数列表......
/** * 最大正方形 * @param matrix char字符型二维数组 * @param matrixRowLen int matrix数组行数 * @param matrixColLen int* matrix数组列数 * @return int整型 */ int min(int a, int b) { return a < b ? a : b; } int max(int a, int b) { return a > b ? a : b; } int solve(char** matrix, int matrixRowLen, int* matrixColLen ) { if (matrixRowLen == 0 || matrixColLen == 0) { return 0; } int res = 0; for (int i = 0; i < matrixRowLen; i++) { for (int j = 0; j < *matrixColLen; j++) { if (matrix[i][j] == '1' && i > 0 && j > 0) { matrix[i][j] = 1 + min(min(matrix[i-1][j-1], matrix[i-1][j]), matrix[i][j-1]); res = max(res, (matrix[i][j] - '0')); } } } return res * res; }
int getSquareArea(vector<int> &v, int k) { if (v.size() < k) return 0; int count = 0; for (int i = 0; i < v.size(); ++i) { if (v[i] != k) count = 0; else ++count; if (count == k) return k * k; } return 0; }
import java.util.*; public class Solution { /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * 最大正方形 * @param matrix char字符型二维数组 * @return int整型 */ public int solve (char[][] matrix) { if (matrix == null || matrix.length == 0 || matrix[0].length == 0) { return 0; } int rows = matrix.length; int cols = matrix[0].length; int[][] dp = new int[rows][cols]; int maxSide = 0; // 初始化第一行和第一列 for (int i = 0; i < rows; i++) { if(matrix[i][0] == '1') dp[i][0] = 1; } for (int j = 0; j < cols; j++) { if(matrix[0][j] == '1') dp[0][j] = 1; } // 动态规划填充dp数组 for (int i = 1; i < rows; i++) { for (int j = 1; j < cols; j++) { if (matrix[i][j] == '1') { dp[i][j] = Math.min(Math.min(dp[i - 1][j], dp[i][j - 1]), dp[i - 1][j - 1]) + 1; maxSide = Math.max(maxSide, dp[i][j]); } } } return maxSide * maxSide; } }
# # 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 # # 最大正方形 # @param matrix char字符型二维数组 # @return int整型 # class Solution: def solve(self , matrix: List[List[str]]) -> int: # write code here if len(matrix) == 0: return 0 if len(matrix[0]) == 0: return 0 res = 0 dp = [[0 for i in range(len(matrix[0]))] for j in range(len(matrix))] for i in range(len(matrix[0])): if matrix[0][i] == '1': dp[0][i] = 1 for j in range(len(matrix)): if matrix[j][0] == '1': dp[j][0] = 1 for i in range(len(matrix)): for j in range(len(matrix[0])): if matrix[i][j] == '1': dp[i][j] = 1 min_len = min(dp[i-1][j], dp[i][j-1]) if matrix[i-min_len][j-min_len] == '1': dp[i][j] += min_len else: dp[i][j] += min_len-1 for i in range(len(matrix)): for j in range(len(matrix[0])): res = max(res, dp[i][j]) return res*res
// 一眼以为是最大矩形。。反正基本一样思路 class Solution { public: /** * 最大正方形 * @param matrix char字符型vector<vector<>> * @return int整型 */ int solve(vector<vector<char> >& matrix) { // write code here if(!matrix.size()||!matrix[0].size()) return 0; vector<vector<int>> dp(matrix.size(),vector<int>(matrix[0].size(),0)); for(int i = 0;i<matrix.size();++i) dp[i][0] = matrix[i][0]=='1'? 1:0; for(int i = 0;i<matrix.size();++i){ for(int j = 1;j<matrix[0].size();++j){ if(matrix[i][j]=='1') dp[i][j] = dp[i][j-1]+1; } } int res = 1; for(int i = 0;i<matrix.size();++i){ for(int j = 0;j<matrix[0].size();++j){ if(dp[i][j]>0){ int dx = dp[i][j];int dy= 1; int x,y; x = j, y= i-1; while(y>=0&&dp[y][x]>0){ dy++; dx = min(dx,dp[y][x]); //确定是不是正方形 if(dx==dy) res = max(res, dx*dy); y--; } } } } return res; } };
class Solution { public: int solve(vector<vector<char> >& matrix) { // corner case if (matrix.empty()) return 0; const size_t m = matrix.size(), n = matrix[0].size(); vector<vector<int>> dp(m + 1, vector<int>(n + 1)); int ans = 0; for (int y = 1; y <= m; ++y) for (int x = 1; x <= n; ++x) if (matrix[y - 1][x - 1] == '1') { // 核心:状态转移方程 dp[y][x] = 1 + min({dp[y - 1][x], dp[y][x - 1], dp[y - 1][x - 1]}); ans = max(ans, dp[y][x]); } return ans * ans; } };
class Solution: def solve(self , matrix: List[List[str]]) -> int: # write code here if not matrix: return 0 n=len(matrix[0]) m=len(matrix) max_len=0 dp=[[0]*(n+1) for _ in range(m+1)] for i in range(1,m+1): for j in range(1,n+1): if matrix[i-1][j-1]=='1': dp[i][j]=min(dp[i-1][j],dp[i][j-1],dp[i-1][j-1])+1 max_len=max(max_len,dp[i][j]) return max_len*max_len
import java.util.*; public class Solution { /** * 最大正方形 * @param matrix char字符型二维数组 * @return int整型 */ public int solve (char [][] matrix) { // write code here int [][]dp = new int [matrix.length][matrix[0].length]; int bc = 0; dp [0][0]=0; for(int i=0;i<dp.length;i++){ dp [i][0]=matrix [i][0]-'0'; } for(int j=0;j<dp [0].length;j++){ dp [0][j]=matrix [0][j]-'0'; } for(int i=1;i<dp.length;i++){ for(int j=1;j<dp [0].length;j++){ if(matrix [i][j]=='0'){ dp [i][j]=0; }else{ int up = dp [i-1][j]; int left = dp [i][j-1]; int ul = dp [i-1][j-1]; if(up==left && up==ul){ dp [i][j]=up+1; }else{ int m = Math.min(up,Math.min(left,ul)); dp [i][j]=m+1; } } } } for(int i=0;i<dp.length;i++){ for(int j=0;j<dp [0].length;j++){ bc = Math.max(bc,dp [i][j]); } } int area = bc*bc; return area; } }
import java.util.*; public class Solution { public int solve (char[][] grap) { int n = grap.length; if(n == 0)return 0; int m = grap[0].length; int f[][] = new int[n + 3][m + 3]; int len = 0; for(int i = 1;i <= n;i++){ for(int j = 1;j <= m;j++){ if(grap[i - 1][j - 1] == '1'){ f[i][j] = Math.min(f[i - 1][j - 1],Math.min(f[i - 1][j],f[i][j - 1])) + 1; len = Math.max(len,f[i][j]); } } } return len * len; } }
class Solution { public: /** dp[i][j]:以第i行j列为最右下角元素 前i行j列的最大边长 当第i行j列元素为1时,dp[i][j]=min(dp[i-1][j],min(dp[i-1][j-1],dp[i][j-1]))+ 1; 当第i行j列元素为0时,dp[i][j]=0; */ int solve(vector<vector<char> >& matrix) { int height = matrix.size(); if(!height) return 0; int width = matrix[0].size(); vector<vector<int> > dp(height+1,vector<int>(width+1, 0)); int maxSide = 0;//最大正方形的宽 for (int i = 1; i <= height; i++) { for (int j = 1; j <= width; j++) { if (matrix[i - 1][j - 1] == '1') { //递推公式 dp[i][j] = min(dp[i - 1][j], min(dp[i - 1][j - 1], dp[i][j - 1]))+ 1; maxSide = max(maxSide, dp[i][j]); } } } //返回正方形的面积 return maxSide * maxSide; } };
public int solve (char[][] matrix) { if(matrix == null || matrix.length == 0) return 0; Stack<Integer> stack = new Stack<>(); int maxRes = 0; int m = matrix.length, n = matrix[0].length; int[] arr = new int[n+2]; for(int i = 0; i < m; i++){ stack.push(0); for(int j = 1; j < n+2; j++){ if(j < n+1){ if(matrix[i][j-1] == '1'){ arr[j]++; }else{ arr[j] = 0; } } while(!stack.isEmpty() && arr[stack.peek()] > arr[j]){ int length = Math.min(arr[stack.pop()], j-stack.peek()-1); maxRes = Math.max(maxRes, length); } stack.push(j); } while(!stack.isEmpty()) stack.pop(); } return maxRes*maxRes; }
public int solve (char[][] matrix) { if(matrix == null || matrix.length == 0) return 0; int m = matrix.length, n = matrix[0].length; int[][] dp = new int[m+1][n+1]; int max = 0; for(int i = 1; i < m+1; i++){ for(int j = 1; j < n+1; j++){ 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(max, dp[i][j]); } } } return max*max; }
class Solution { public: int solve(vector<vector<char> >& matrix) { // write code here int maxSide=0; int m=matrix.size(),n=matrix[0].size(); vector<vector<int>> dp(m,vector<int>(n)); //动态规划 //数组含义:dp[i][j]表示当前最大边长 //递推公式:正方形,当遍历到一个1时,需要判断左上,上,左是否都为1.都为1则加1,不为1则不变由于是01矩阵,只需要利用min函数即可 //初始化:dp数组边长应该都为0,不需要特别初始化 //遍历顺序,根据递推公式,从上到下,从左到右即可 for(int i=0;i<m;i++){ for(int j=0;j<n;j++){ if(matrix[i][j]=='1'){ if(i==0||j==0) dp[i][j]=1;//特殊情况,没有左上,上,左.默认边长为1的正方形 else dp[i][j]=min(dp[i-1][j-1],min(dp[i-1][j],dp[i][j-1]))+1; } maxSide=max(maxSide,dp[i][j]);//每次计算完需要比较存储 } } return maxSide*maxSide; } };
dp 数组含义: dp[i][j]: 以 matrix[i - 1][j - 1] 为右下角的最大正方形边长。
class Solution { public: /** * 最大正方形 * @param matrix char字符型vector<vector<>> * @return int整型 */ int solve(vector<vector<char> >& matrix) { // write code here int row = matrix.size(); int col = matrix[0].size(); int maxSize = 0; // dp[i][j]: 以 matrix[i - 1][j - 1] 为右下角的最大正方形边长。 vector<vector<int>> dp(row + 1, vector<int>(col + 1, 0)); for (int i = 1; i <= row; i++) { for (int j = 1; j <= col; j++) { if (matrix[i - 1][j - 1] == '1') { dp[i][j] = min( dp[i][j - 1], min(dp[i - 1][j - 1], dp[i - 1][j]) ) + 1; maxSize = maxSize < dp[i][j] ? dp[i][j] : maxSize; } else { dp[i][j] = 0; } } } return maxSize * maxSize; } };
用dp[i][j]表示以matrix[i][j]为右下角的全为1组成的最大正方形的边长,则:
1. 若matrix[i][j] == 0, 则dp[i][j] = 0
2. 若matrix[i][j] == 1, 则dp[i][j] = min{dp[i-1][j], dp[i][j-1], dp[i-1][j-1]} + 1
原因可以看下面这张图: