Max Submatrix:求矩阵中和最大的子矩阵。
根据提示,先回顾下如何求最大子数组的和(16.17):只需要依次将数组中的元素进行累加,如果目前的累加和变大了,就进行更新,如果目前的累加和变成了负数,那么就将累加和重置为0
,这样就在O(n)
的时间内找到了最大子数租的和。
如果能将某一个子矩阵压缩成一行,那么就可以用上面的方法进行计算了。假设要压缩的矩阵起始行为startRow
,终止行为endRow
,当求出了每一列的和之后,该矩阵就压缩为了一行,然后应用上面的方法,可以在O(r ^ 3 * c)
的时间内计算出结果:前两个r
是枚举startRow
和endRow
,第3
个r
是对[startRow, endRow]
之间的每一列求和,c
为求解最大子数组和的复杂度。当然,4
次方的复杂度超时了。
class Solution {
public:
vector<int> getMaxMatrix(vector<vector<int>>& matrix) {
vector<int> ans;
int max = INT_MIN;
for(int startRow = 0; startRow < matrix.size(); startRow++)
{
for(int endRow = startRow; endRow < matrix.size(); endRow++)
{
vector<int> partialSum(matrix[0].size(), 0);
for(int c = 0; c < matrix[0].size(); c++)
{
for(int r = startRow; r <= endRow; r++)
{
partialSum[c] += matrix[r][c];
}
}
int sum = 0, startCol = 0;
for(int endCol = 0; endCol < matrix[0].size(); endCol++)
{
sum += partialSum[endCol];
if(max < sum){
max = sum;
ans = { startRow, startCol, endRow, endCol };
}
if(sum < 0){
sum = 0;
startCol = endCol + 1;
}
}
}
}
return ans;
}
};
从代码中发现,每当endRow
变大时,都需要重新计算partialSum
,这里浪费了很多时间。在startRow
不变的情况下,新的partialSum
可以利用上一次计算的结果,将endRow
这一行中的元素累加到partialSum
上就得到了新的partialSum
。
class Solution {
public:
vector<int> getMaxMatrix(vector<vector<int>>& matrix) {
vector<int> ans;
int max = INT_MIN;
for(int startRow = 0; startRow < matrix.size(); startRow++)
{
vector<int> partialSum(matrix[0].size(), 0);
for(int endRow = startRow; endRow < matrix.size(); endRow++)
{
int sum = 0, startCol = 0;
for(int endCol = 0; endCol < matrix[0].size(); endCol++)
{
partialSum[endCol] += matrix[endRow][endCol];
sum += partialSum[endCol];
if(max < sum){
max = sum;
ans = { startRow, startCol, endRow, endCol };
}
if(sum < 0){
sum = 0;
startCol = endCol + 1;
}
}
}
}
return ans;
}
};