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

Grandyang發表於2016-05-12

 

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

 

CareerCup All in One 題目彙總

 

相關文章