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 k和Maximum 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; }