leetcode 01最大矩形求解的兩種方法
問題描述:給定一個填充了 0 和 1 的二進位制矩陣,找到最大的只包含 1 的矩形並返回其面積。
方法一:轉化為直方圖,以每一行產生一個直方圖,從被選中行累加“1”的數目,直到遇到0。然後轉化為求直方圖的最大矩形,用堆疊法o(n),或者中心擴散法o(n^2)求直方圖的最大矩形。總複雜度o(n^3)或o(n^4)程式碼如下:
int maximalRectangle(vector<vector<char> > &matrix) { if(matrix.size()==0) return 0; int* hist = new int[matrix[0].size()]; memset(hist, 0, sizeof(int)*matrix[0].size()); int max_ = 0; for(int i=0; i<matrix.size(); i++){ for(int j=0; j<matrix[0].size(); j++){ if(matrix[i][j]=='1') *(hist+j) += 1; else *(hist+j) = 0; } max_ = max(max_, maxRectInHistogram(hist, matrix[0].size()) ); } return max_; } int maxRectInHistogram(int hist[], int n) { int max_ = hist[0]; // 最大面積 int j = 0, k = 0, temp =0; for(int i=0; i<n; i++){ j = i, k = i; while(j < n&&hist[j] >= hist[i])j++; while(k >= 0&&hist[k] >=hist[i])k--; temp = (j-k-2 + 1)*hist[i]; max_ = max(temp,max_); } return max_; }
方法二:動態規劃法,複雜度o(n^2),其子問題為,以某一點為右下角的最大矩形,將其對角點記為point[i][j],則可以通過對角點計算長寬,從而 計算面積。
1. 分析當前點(i,j)為0,則以該點為右下角的矩形不存在,可以記錄其對應的左上角座標為(0,0)非法注意座標值預設從(1,1)開始,即無對角點,且面積arra[i][j]為0,
2. 如果(i,j)為1則分四種情況討論,
a. (i-1,j)和(i,j-1)點都為‘0’則其對角點為其本身,最大面積為1;
b. (i-1,j)為0而點(i,j-1)為1,則(i,j)對角點橫座標為i,縱座標為(i,j-1)的縱座標,可以很容易計算出最大面積
c. (i,j-1)為0而點(i-1,j)為1為b的對偶情況,對角點縱座標為j,橫座標為(i-1,j)的橫座標,可以很容易計算出最大面積
d. 左方和上方的點都為1,則可分兩種情況(改天傳圖片,講解反證分析過程)。
d.1 部分重疊相交,通過反證法分析可得,這種情況最大對角點可能為左方點的對角點或者右上方點的對角點
d.2十字相交重疊,則要先求出除本身的點外的三個交點的對角點座標,三個點座標比較,縱橫座標都取其中的最大 值就是,(i,j)的對角點則也可通過反證法分析得到,離原點最近的交點即為最大對角點
程式碼如下:
struct Point{
int x;
int y;
};
Point point[100][100] = {(0,0)};
int area[100][100] = {0};//統計面積的陣列,每個右下角
int maximalRectangle(vector<vector<char>>& matrix) {
int len1 = matrix.size();
int len2 = matrix[0].size();
if(len1 == 0)
return 0;
int max = 0;
for(int i = 1; i <= len1; i++)
for(int j = 1; j <= len2; j++){
if(matrix[i-1][j-1] == '1'){
if(point[i][j-1].x != 0&&point[i-1][j].x != 0){
if(point[i][j-1].x>= point[i-1][j].x&&point[i][j-1].y<=point[i-1][j].y){//情況1部分重疊
int temp1 = (i - point[i-1][j].x + 1)*(j - point[i-1][j].y + 1);
int temp2 = (i - point[i][j-1].x + 1)*(j - point[i][j-1].y + 1);
area[i][j] = temp1 > temp2?temp1 : temp2;
point[i][j] = temp1 > temp2?point[i-1][j]:point[i][j-1];
}
else if(point[i][j-1].x< point[i-1][j].x&&point[i][j-1].y>point[i-1][j].y){//十字交叉
//area[i][j] = (i-point[i-1][j].x + 1)*(j-point[i][j-1].y + 1);