最大子矩阵和
因为觉得参考链接讲解依然不够清楚,所以写了这篇博客。
好吧其实是因为今天面试了这道题,自己想了很久没想出来所以想写一下。
啊 求offer
问题重述
求一个n x n的矩阵 M 的最大子矩阵和。
比如在如下这个矩阵中:
0 -2 -7 0
9 2 -6 2
-4 1 -4 1
-1 8 0 -2
拥有最大和的子矩阵为:
9 2
-4 1
-1 8
其和为15。
解答
这里只讲O(n3)的解法,也就是最优解。暴力解实在没有讲解的必要。
一维的解决方案
首先要简化问题。考虑一维的情况,这就是一个“最大子段和问题”,有O(n)的解法,具体自己去查。
将二维问题分解
假设最大和子矩阵的行数为R,R∈[1,n]。
子问题:对矩阵M所有行数为R的子矩阵,它们的最大和是多少。答案记为SR。
显然 MAX(S1,S2……,Sn) 即为本题的答案。
子问题求解
子问题:对矩阵M所有行数为R的子矩阵,它们的最大和是多少。
对任意行数为R的子矩阵,矩阵M中必然存在一个连续的R行包含该子矩阵。
我们从M中任取连续的R行作为“条状矩阵”,有n-R+1中取法。
假设R=2,则从M中任取连续的2行作为“条状矩阵”,有n-1种取法。
条状矩阵的维度为R X n。
R=2时条状矩阵的维度为2 X n。
孙问题:对每一个(共n-R+1个)条状矩阵,求其R行子矩阵最大的矩阵和。
对得到的n-R+1个最大矩阵和求最大值,得到矩阵M的R行子矩阵最大矩阵和,即子问题答案。
孙问题求解
孙问题:对每一个(共n-R+1个)条状矩阵,求其R行子矩阵最大的矩阵和。
条状矩阵的维度为R X n,我们要求R行子矩阵,注意到两者的行维度是一样的,都是R行。
也就是说,我们只需要考虑子矩阵是从条状矩阵的第几列到第几列,不必考虑行,因为行维度相同,一旦列数确定,该列所有的行都在子矩阵中。
对条状矩阵同一列的所有元素而言,他们要么都在子矩阵中,要么都不在子矩阵中,不可能分离。
因此我们将同一列元素都相加,他们的和组成一个一维数组,对这个数组求“最大子段和问题”就得到了孙问题的解答。
时间复杂度分析和实现
总时间复杂度O(n3)
R=1时有n个条状矩阵,R=2时有n-1个条状矩阵……总共有
∑
1
n
1
=
(
1
+
n
)
n
/
2
\sum_1^n 1 = (1+n)n/2
1∑n1=(1+n)n/2
个条状矩阵。
对每一个条状矩阵,求解孙问题的复杂度为 O(n),因此总复杂度为O(n3)。
孙问题的O(n)
孙问题需要优化才能O(n)。
“最大子段和问题”是O(n)的,这没有什么问题。
但是下面这一步(将其称为“劣质步骤”)
同一列元素都相加,他们的和组成一个一维数组
复杂度是O(R*n),这会使我们的时间复杂度恶化,我们要优化。
建立一个与M相同维度的矩阵J,其中元素J[x][y]代表M第y列前x行的和。
劣质步骤中的求和不再一个一个加,而是用该列的前k项和减去前h-1项和就得到了该列第h到k项的和。
这样,劣质步骤中的求和操作就可以O(1)地完成,劣质步骤总时间复杂度优化为O(n)。
例如,对R=3的一个条形矩阵
9 2 -6 2
-4 1 -4 1
-1 8 0 -2
它是M矩阵中的第2、3、4行,我们优化过的求和可以使用如下代码
for(int i=0;i<n;i++){
res[i]=J[4][i]-J[1][i];
}
建立矩阵J的时间为O(n2),因为本题算法为O(n3),所以不影响。