1. 程式人生 > >[CareerCup] 18.12 Largest Sum Submatrix 和最大的子矩陣

[CareerCup] 18.12 Largest Sum Submatrix 和最大的子矩陣

18.12 Given an NxN matrix of positive and negative integers, write code to find the submatrix with the largest possible sum.

這道求和最大的子矩陣,跟LeetCode上的Maximum Size Subarray Sum Equals kMaximum Subarray很類似。這道題不建議使用brute force的方法,因為實在是不高效,我們需要借鑑上面LeetCode中的建立累計和矩陣的思路,我們先來看這道題的第一種解法,由於建立好累計和矩陣,那麼我們通過給定了矩陣的左上和右下兩個頂點的座標可以在O(1)的時間內快速的求出矩陣和,所以我們要做的就是遍歷矩陣中所有的子矩陣,然後比較其矩陣和,返回最大的即可,時間複雜度為O(n4

)。

解法一:

vector<vector<int>> precompute(vector<vector<int>> &matrix) {
    vector<vector<int>> sumMatrix = matrix;
    for (int i = 0; i < matrix.size(); ++i) {
        for (int j = 0; j < matrix[i].size(); ++j) {
            if (i == 0 && j == 0
) { sumMatrix[i][j] = matrix[i][j]; } else if (j == 0) { sumMatrix[i][j] = sumMatrix[i - 1][j] + matrix[i][j]; } else if (i == 0) { sumMatrix[i][j] = sumMatrix[i][j - 1] + matrix[i][j]; } else { sumMatrix[i][j]
= sumMatrix[i - 1][j] + sumMatrix[i][j - 1] - sumMatrix[i - 1][j - 1] + matrix[i][j]; } } } return sumMatrix; } int compute_sum(vector<vector<int>> &sumMatrix, int i1, int i2, int j1, int j2) { if (i1 == 0 && j1 == 0) { return sumMatrix[i2][j2]; } else if (i1 == 0) { return sumMatrix[i2][j2] - sumMatrix[i2][j1 - 1]; } else if (j1 == 0) { return sumMatrix[i2][j2] - sumMatrix[i1 - 1][j2]; } else { return sumMatrix[i2][j2] - sumMatrix[i2][j1 - 1] - sumMatrix[i1 - 1][j2] + sumMatrix[i1 - 1][j1 - 1]; } } int get_max_matrix(vector<vector<int>> &matrix) { int res = INT_MIN; vector<vector<int>> sumMatrix = precompute(matrix); for (int r1 = 0; r1 < matrix.size(); ++r1) { for (int r2 = r1; r2 < matrix.size(); ++r2) { for (int c1 = 0; c1 < matrix[0].size(); ++c1) { for (int c2 = c1; c2 < matrix[0].size(); ++c2) { int sum = compute_sum(sumMatrix, r1, r2, c1, c2); res = max(res, sum); } } } } return res; }

其實這道題的解法還能進一步優化到O(n3),根據LeetCode中的那道Maximum Subarray的解法,我們可以對一維陣列求最大子陣列的時間複雜度優化到O(n),那麼我們可以借鑑其的思路,由於二維陣列中遍歷所有的列數相等的子矩陣的時間為O(n2),每一行的遍歷是O(n),所以整個下來的時間複雜度即為O(n3),參見程式碼如下:

解法二:

int max_subarray(vector<int> &array) {
    int res = 0, sum = 0;
    for (int i = 0; i < array.size(); ++i) {
        sum += array[i];
        res = max(res, sum);
        sum = max(sum, 0);
    }
    return res;
}

int max_submatrix(vector<vector<int>> &matrix) {
    if (matrix.empty() || matrix[0].empty()) return 0;
    int res = 0;
    for (int r1 = 0; r1 < matrix.size(); ++r1) {
        vector<int> sum(matrix[0].size());
        for (int r2 = r1; r2 < matrix.size(); ++r2) {
            for (int c = 0; c < matrix[0].size(); ++c) {
                sum[c] += matrix[r2][c];
            }
            int t = max_subarray(sum);
            res = max(res, t);
        }
    }
    return res;
}