Given a 2D binary matrix filled with 0's and 1's, find the largest square containing all 1's and return its area.
For example, given the following matrix:
1 0 1 0 01 0 1 1 1
1 1 1 1 1
1 0 0 1 0
Return 4.
Credits:
Special thanks to @Freezen for adding this problem and creating all test cases.
Hide Tags Dynamic Programming
分析:要找到全爲'1'的正方形最大面積,思路和64題的Minimum Path Sum很類似。從一個矩陣的左上方走到右下方,找到滿足條件的所有正方形,求得最大的一個即可。
這樣可以用一個二維數組dp[][]來存放計算過程中臨時最大值。其中dp[i][j]表示以matrix[i][j]爲右下角端點的全爲'1'的最大的方陣的邊長,那麼最後求出求出最大的邊長max,即可得到最大面積max * max。
那麼遞推公式是怎樣的呢?最暴力的方法就是動筆在紙上挨着畫幾個例子,歸納法找規律:首先,但看第0行和第0列,由於沒有三個前向鄰居(每個元素的左邊、上變和左上的元素),而體重要求的是方陣的面積,因此對於dp第0行和第0列,直接等於matrix中的字符對應的數字即可。
然後問題來了,如何更新dp[i][j](i>0 && j>0)?要計算全爲'1'的方陣,那麼
當matrix[i][j]爲'0'時,以當前節點爲右下角節點時,最大的全爲'1'的方陣不存在,此時dp[i][j] = 0;
當matrix[i][j]爲'1'時,如果當前節點位置對應的dp中節點左上相鄰的三個元素均均爲r,則dp[i][j] = r+1
如果當前節點位置對應的dp中節點左上相鄰的三個元素不相等,那麼dp[i][j] = min(三個前向鄰居)+1
合併起來就是dp[i][j] = min(dp[i-1][j-1],dp[i][j-1],dp[i-1][j]) + 1;
以下是C++實現代碼:
/**///////////////////////////12ms*/
class Solution {
public:
int min(int a,int b,int c){ //返回三個數中最小值
int tmp = a < b ? a:b;
return (tmp < c) ? tmp : c;
}
int maximalSquare(vector<vector<char>>& matrix) {
int m = matrix.size();
if(m == 0) //爲空,則返回0
return 0;
int n = matrix[0].size();
vector<vector<int>> dp(m,vector<int>(n,0)); //臨時二維數組
int max = 0; //最大邊長變量
for(int i = 0; i < m; i++){ //初始化第0列
if(matrix[i][0] == '0' )
dp[i][0] = 0;
else
dp[i][0] = 1;
if(max < dp[i][0]) //同時更新最大邊長
max = dp[i][0];
}
for(int j = 0; j < n; j++){ //初始化第0行
if(matrix[0][j] == '0' )
dp[0][j] = 0;
else
dp[0][j] = 1;
if(max < dp[0][j]) //同時更新最大邊長
max = dp[0][j];
}
for(int i = 1; i < m; i++){ //計算非0行和非0列元素作爲最右下角元素的全爲'1'的最大邊長
for(int j = 1; j < n; j++){
if(matrix[i][j] == '0' ) //matrix[i][j] == 0,那麼該位置對應的最大邊長爲0
dp[i][j] = 0;
else{ matrix[i][j]==1的時候,用遞推公式迭代
dp[i][j] = min(dp[i-1][j-1],dp[i][j-1],dp[i-1][j]) + 1;
if(max < dp[i][j]) //更新最大邊長
max = dp[i][j];
}
}
}
return max * max; //返回最大面積
}
};