1. 程式人生 > >leetcode 01最大矩形求解的兩種方法

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);