1. 程式人生 > >Maximum Submatrix & Largest Rectangle

Maximum Submatrix & Largest Rectangle

org iso oid pointers 所有 tin test www. define

相關題型

問題一(最大和子矩陣) : 有一個 m x n 的矩陣,矩陣的元素可正可負。請找出該矩陣的一個子矩陣(方塊),使得其所有元素之和在所有子矩陣中最大。(問題來源:http://acm.pku.edu.cn/JudgeOnline/problem?id=1050)

問題二( 最大 0/1 方塊) :有一個 m x n 的矩陣,元素為 0 或 1。一個子矩陣,如果它所有的元素都是 0, 或者都是 1,則稱其為一個 0-聚類 或 1-聚類,統稱聚類(Cluster)。請找出最大的聚類(元素最多的聚類)(面試題)

這兩個問題,除了都是在矩陣上操作之外,似乎沒有什麽共同之處。其實不然。事實上,它們可以用同一個思路解決。該思路來源於下面的一個問題,具體地說,就是把前兩個問題化歸成多個問題三:

問題三(和最大的段) :有 n 個有正有負的數排成一行,求某個連續的段,使得其元素之和最大。(問題來源:某面試題。事實上,這也是一道經典題目,具體參考 http://en.wikipedia.org/wiki/Maximum_subarray_problem)

問題四(最大長方形) : 有一個有 n 個項的統計直方圖,假定所有的直方條 (bar) 的寬度一樣。在所有邊與 x 軸 和 y 軸平行的長方形中,求該被該直方圖包含的面積最大的長方形。(問題來源:面試經典題目)

參考

  • Maximum Submatrix & Largest Rectangle
  • [leetcode]221. Maximal Square
分析:動態規劃,從左上角開始,如果當前位置為1,那麽到當前位置包含的最大正方形邊長為左/左上/上的值中的最小值加一,因為邊長是由短板控制的。
  • 最大子矩陣和
最大子矩陣和問題可以類比於最大字段和問題,從一維變成二維,dp思路,在輸入的時候做一個處理,讓a[i,j]變為存放前i行j列的和,降低復雜度。狀態轉移方程為sum[k+1]=sum[k]<0?0:sum[k]+a[i,j];表示第k行i到j的和。因為a[i,j]為存放前i行j列的和,所以a[i,j]=a[k,j]-a[k,i-1]; 
  • Maximum sum rectangle in a 2D matrix | DP-27
// Program to find maximum sum subarray in a given 2D array
#include <stdio.h>
#include <string.h>
#include <limits.h>
#define ROW 4
#define COL 5
 
// Implementation of Kadane's algorithm for 1D array. The function 
// returns the maximum sum and stores starting and ending indexes of the 
// maximum sum subarray at addresses pointed by start and finish pointers 
// respectively.
int kadane(int* arr, int* start, int* finish, int n)
{
    // initialize sum, maxSum and
    int sum = 0, maxSum = INT_MIN, i;
 
    // Just some initial value to check for all negative values case
    *finish = -1;
 
    // local variable
    int local_start = 0;
 
    for (i = 0; i < n; ++i)
    {
        sum += arr[i];
        if (sum < 0)
        {
            sum = 0;
            local_start = i+1;
        }
        else if (sum > maxSum)
        {
            maxSum = sum;
            *start = local_start;
            *finish = i;
        }
    }
 
     // There is at-least one non-negative number
    if (*finish != -1)
        return maxSum;
 
    // Special Case: When all numbers in arr[] are negative
    maxSum = arr[0];
    *start = *finish = 0;
 
    // Find the maximum element in array
    for (i = 1; i < n; i++)
    {
        if (arr[i] > maxSum)
        {
            maxSum = arr[i];
            *start = *finish = i;
        }
    }
    return maxSum;
}
 
// The main function that finds maximum sum rectangle in M[][]
void findMaxSum(int M[][COL])
{
    // Variables to store the final output
    int maxSum = INT_MIN, finalLeft, finalRight, finalTop, finalBottom;
 
    int left, right, i;
    int temp[ROW], sum, start, finish;
 
    // Set the left column
    for (left = 0; left < COL; ++left)
    {
        // Initialize all elements of temp as 0
        memset(temp, 0, sizeof(temp));
 
        // Set the right column for the left column set by outer loop
        for (right = left; right < COL; ++right)
        {
           // Calculate sum between current left and right for every row 'i'
            for (i = 0; i < ROW; ++i)
                temp[i] += M[i][right];
 
            // Find the maximum sum subarray in temp[]. The kadane() 
            // function also sets values of start and finish.  So 'sum' is 
            // sum of rectangle between (start, left) and (finish, right) 
            //  which is the maximum sum with boundary columns strictly as
            //  left and right.
            sum = kadane(temp, &start, &finish, ROW);
 
            // Compare sum with maximum sum so far. If sum is more, then 
            // update maxSum and other output values
            if (sum > maxSum)
            {
                maxSum = sum;
                finalLeft = left;
                finalRight = right;
                finalTop = start;
                finalBottom = finish;
            }
        }
    }
 
    // Print final values
    printf("(Top, Left) (%d, %d)\n", finalTop, finalLeft);
    printf("(Bottom, Right) (%d, %d)\n", finalBottom, finalRight);
    printf("Max sum is: %d\n", maxSum);
}
 
// Driver program to test above functions
int main()
{
    int M[ROW][COL] = {{1, 2, -1, -4, -20},
                       {-8, -3, 4, 2, 1},
                       {3, 8, 10, 1, 3},
                       {-4, -1, 1, 7, -6}
                      };
 
    findMaxSum(M);
 
    return 0;
}

Maximum Submatrix & Largest Rectangle