题目
一个N*M的矩阵,其中元素都为整数,求最大子矩阵的和
思考
如果用穷举法,子矩阵左上角的坐标(i_1,i_2)有NM种可能,右下角坐标(j_1,j_2)有NM种可能,遍历矩阵内容求和复杂度为O(NM),因此穷举的复杂度为O((NM)^3)
先回顾另一个题:求最大子序列,有两种方法
###动态规划
def maxSum(nums):
tmp = sum = nums[0]
if len(nums) != 1: #单个就直接输出
for i in range(1,len(nums)):
if tmp <= 0: #意味着增大的序列已经终止,从最大max到当前tmp的序列都是递减,没有意义,需要重新考虑
tmp = nums[i]
else:
tmp += nums[i]
sum = max(tmp,sum)
return sum
分治:
def leetcode(s):
if len(s) == 1:
return s[0];
center = len(s)//2
left = s[:center]
right = s[center:]
left_max = leetcode(left)
right_max = leetcode(right)
c2left_max = left[-1]
c2l_temp = 0
for i in left[::-1]:
c2l_temp += i
if c2l_temp > c2left_max:
c2left_max = c2l_temp;
c2right_max = right[0]
c2r_temp = 0
for j in right:
c2r_temp += j
if c2r_temp > c2right_max:
c2right_max = c2r_temp;
return max(left_max,right_max,c2left_max+c2right_max)
这里我们考虑将二维矩阵进行降维处理,通过确定的行范围,将列范围进行求和(行在变化过程中,对列的选取由最大子序列完成),压缩为一维数组,将问题转换为求一维数组最大子序列。
import sys
import numpy
def MaxSubArray(array): # 最大子序列
rs = array[0]
tmp = rs;
n = len(array)
start = 0 #最大子序列起始位置
end = 0
if n != 1:
for i in range(1,n):
tmp += array[i];
if tmp <= 0:
tmp = 0
start = i + 1;
if tmp > rs:
rs = tmp
end = i
#print(start,end)
return rs,start,end
def MaxSubMatrix(matrix,n,m):
rs = 0;
rs_start = (0,0) #最大子矩阵坐标
rs_end = (0,0)
for i in range(n): #遍历起始行
tmp_sum = [0 for _ in range(m)] # numpy.zeros(m)清零,每一列的和
for j in range(i,n): #结束行
for k in range(m): #将每一列降维
tmp_sum[k] += matrix[j][k] #每一列求和
tmp_max,y1,y2 = MaxSubArray(tmp_sum)
if(tmp_max > rs):
rs_start = (i,y1)
rs_end = (j,y2)
rs = tmp_max;
return rs,rs_start,rs_end
if __name__ == "__main__":
message = sys.stdin.readline().strip().split()
n,m = int(message[0]),int(message[1]);
matrix = []
# matrix = numpy.arange(n*m).reshape(n,m)
for i in range(n):
matrix.append([])
nums = sys.stdin.readline().strip().split()
for j in range(m):
matrix[i].append(int(nums[j]))
print(matrix)
print(MaxSubMatrix(matrix,n,m))
复杂度分析
1.行范围的选取O(nn)
2.对列求和进行降维处理O(m),这一步可以预先算好
3.降维后,求最大子序列O(m)
因此复杂度为O(nn*m)