0. 题目
给定一个正整数、负整数和 0 组成的 N × M 矩阵,编写代码找出元素总和最大的子矩阵。
返回一个数组 [r1, c1, r2, c2],其中 r1, c1 分别代表子矩阵左上角的行号和列号,r2, c2 分别代表右下角的行号和列号。若有多个满足条件的子矩阵,返回任意一个均可。
注意:本题相对书上原题稍作改动
示例:
输入:
[
[-1,0],
[0,-1]
]
输出:[0,1,0,1]
解释:输入中标粗的元素即为输出所表示的矩阵
说明:
1 <= matrix.length, matrix[0].length <= 200
1. 题解
a. 暴力
直接使用暴力求解,依次枚举左上、左下、右上、右下坐标,
之后求和Matrix[左上x:右下x][左上y:右下y],
得到当前值temp,若temp>MaxValue,则更新MaxValue与坐标ans
class Solution:
def getMaxMatrix(self, matrix: List[List[int]]) -> List[int]:
m=len(matrix)
n=len(matrix[0])
MaxValue=-float('inf')
ans=[0,0,0,0]
for l1 in range(m): #枚举左上点的x
for l2 in range(n): #枚举左上点的y
for r1 in range(l1,m): #枚举右下x
for r2 in range(l2,n): #枚举右下y
temp=0
#计算当前子矩阵的和
for i in range(l1,r1+1):
for j in range(l2,r2+1):
temp+=matrix[i][j]
#如果子矩阵的值大于之前的最大值,则renew MaxValue和ans
if temp>MaxValue:
MaxValue=temp
ans=[l1,l2,r1,r2]
return ans
暴力求解,时间复杂度为O((m*n)^3),空间复杂度O(1),会TLE
b.前缀+dp
将二维问题降维,转化为一维最大子序列的问题
时间复杂度O((m*n)^2),空间复杂度O(n)
class Solution:
def getMaxMatrix(self, matrix: List[List[int]]) -> List[int]:
m,n=len(matrix),len(matrix[0])
ans=[0]*4
MaxValue=-float('inf')
for i in range(m): #从第i行开始
for j in range(i,m): #以第j行结尾
temp=[0]*n #存储i到j行的前缀和
begin=0 #子序列开始的位置
dp=0 #dp的初始值
#计算从第i行到第j行的前缀和temp[n](共n列),!此步骤有大量的重复运算!
for k in range(n):
for l in range(i,j+1)
temp[k]+=matrix[l][k]
#求解最大子序列
if dp<0:
dp=temp[k]
begin=k
else:
dp=dp+temp[k]
if dp>MaxValue:
MaxValue=dp
ans=i,begin,j,k
return ans
c.前缀+dp+优化
将二维问题降维,转化为一维最大子序列问题
b方法中,我们可以明显感受到,在计算每一列的和时有大量的重复计算,我们对此进行优化,将计算过的值存储下来以复用
时间复杂度O(m^2*n),空间复杂度O(n)
class Solution:
def getMaxMatrix(self, matrix: List[List[int]]) -> List[int]:
m,n=len(matrix),len(matrix[0])
ans=[0]*4
MaxValue=-float('inf')
for i in range(m):
temp=[0]*n #如果起始行不变,就没必要从零开始计算,可以把之前行的和存储起来
for j in range(i,m):
begin=0 #起始位置清0
dp=0 #dp清0
for k in range(n):
temp[k]+=matrix[j][k]
if dp<0:
dp=temp[k]
begin=k
else:
dp=dp+temp[k]
if dp>MaxValue:
MaxValue=dp
ans=i,begin,j,k
return ans