在一個由 0 和 1 組成的二維矩陣內,找到只包含 1 的最大正方形,並返回其面積。
示例:
輸入:
1 0 1 0 0
1 0 1 1 1
1 1 1 1 1
1 0 0 1 0
輸出: 4
不需要額外空間 直接原地dp
寫得有點醜,沒有大佬們的好看。
第一個for遍歷1~max_edge,也就是最長的邊。
第二三個for,判斷matrix[i][j]=='1' && matrix[i-1][j]=='1' && matrix[i][j-1]=='1' && matrix[i-1][j-1]=='1'
,也就是當前位置,以及它左上角的位置,以及左邊的位置,上邊的位置都爲1,說明可以組成邊長爲當前len的正方形。注意len爲1時只要找到一個就可以break了,len>1時,比如len==2,要遍歷所有可能的位置,更新matrix[i][j],這個是接下來len++後判斷需要使用的。最後可以做的剪枝,若在當前len下不能更新找到更大的正方形,則接下來更不可能找到了,直接break。
【注意】:這個matrix在不同的len下含義的不同的喔。
public static int maximalSquare(char[][] matrix) {
if (matrix==null || matrix.length==0 || matrix[0]==null || matrix[0].length==0) return 0;
int row = matrix.length;
int col = matrix[0].length;
int max_edge = Math.min(row, col);
int max_area = 0;
for (int len = 1;len<=max_edge;len++){
boolean flag = false;
for (int i = row-1;i>=len-1;i--){
for (int j = col-1;j>=len-1;j--){
if (matrix[i][j]=='1' && len==1) {
max_area = Math.max(max_area, len * len);
flag = true;
break;
}
if (len!=1) {
if (matrix[i][j]=='1' && matrix[i-1][j]=='1' &&
matrix[i][j-1]=='1' && matrix[i-1][j-1]=='1'){
flag=true;
max_area = Math.max(max_area, len*len);
}else {
matrix[i][j]=0;
}
}
}
if (flag && len==1) break;
}
if (flag==false)
break;
}
return max_area;
}
動態規劃
我們用一個例子來解釋這個方法:
0 1 1 1 0
1 1 1 1 1
0 1 1 1 1
0 1 1 1 1
0 0 1 1 1
- 我們用 0 初始化另一個矩陣 dp,維數和原始矩陣維數相同;
- dp(i,j) 表示的是由 1 組成的最大正方形的邊長;
- 從 (0,0) 開始,對原始矩陣中的每一個 1,我們將當前元素的值更新爲
dp(i, j)=min(dp(i−1, j), dp(i−1, j−1), dp(i, j−1))+1
- 我們還用一個變量記錄當前出現的最大邊長,這樣遍歷一次,找到最大的正方形邊長 maxsqlen,那麼結果就是 maxsqlen^2。
可以通過下面的圖來理解該工作原理:
public class Solution {
public int maximalSquare(char[][] matrix) {
int rows = matrix.length, cols = rows > 0 ? matrix[0].length : 0;
int[][] dp = new int[rows + 1][cols + 1];
int maxsqlen = 0;
for (int i = 1; i <= rows; i++) {
for (int j = 1; j <= cols; j++) {
if (matrix[i-1][j-1] == '1'){
dp[i][j] = Math.min(Math.min(dp[i][j - 1], dp[i - 1][j]), dp[i - 1][j - 1]) + 1;
maxsqlen = Math.max(maxsqlen, dp[i][j]);
}
}
}
return maxsqlen * maxsqlen;
}
}
複雜度分析
- 時間複雜度:O(mn)O(mn)。
- 空間複雜度:O(mn)O(mn),用了一個大小相同的矩陣 dp。