最大子数组问题:
############################################ 最大非空子数组 2016.4.4
##test = [0,-2,3,5,-1,2]
test = [-1,-2,-3,-5,-1,-2]
def maxsubarray(test): # 无法处理全负数的情况
curmax = 0
allmax = 0
for x in test:
curmax +=x
if curmax<0:
curmax = 0
allmax = max(allmax, curmax)
return allmax
# 动态规划思路
def maxsubarray2(test): # 可以处理全负数的情况
nstart = test[-1]
# 以i开头的最大子数组 nstart[i] = max(test[i], nstart[i+1])
allmax = test[-1]
for i in range(len(test)-2,-1,-1):
nstart = max(test[i], nstart+test[i])
allmax = max(allmax, nstart)
return allmax
print maxsubarray(test)
print maxsubarray2(test)
最大子数组问题扩展到2维平面上:
类似于图像处理中常用的积分图像,需要一个O(M*N)的预处理过程。
############################################ 二维矩阵的最大子数组 2016.4.4
# 类似于积分图像的概念
import random,pprint,time
h,w,ran = 100,100,10
test = [[random.randint(-ran,ran) for i in range(w)] for i in range(h)]
##pprint.pprint(test)
def submaxarray2d(test):
# 计算积分图像
rows = len(test)
cols = len(test[0])
# mat 补边界,方便运算
mat = [[0]*(cols+1) for i in range(rows+1)]
# 0行0列需预处理 (时间复杂度m*n)
for i in range(rows):
for j in range(cols):
mat[i+1][j+1] = mat[i+1][j]+mat[i][j+1]-mat[i][j]+test[i][j]
## def add(a1,a2):
## return a1+a2
## mat = reduce(add, mat) # 拉成一维
maxvalue,thei,thej = 0,None,None # (时间复杂度m*n*m*n)
for i1 in range(rows+1):
for j1 in range(cols+1):
for i2 in range(i1,rows+1):
for j2 in range(j1,cols+1):
cut = mat[i2][j2]-mat[i2][j1]-mat[i1][j2]+mat[i1][j1]
if cut>maxvalue:
maxvalue = cut
thei = (i1, j1)
thej = (i2, j2)
return maxvalue,thei,thej
s = time.clock()
print submaxarray2d(test) # 100*100的矩阵耗时7.17203秒
print time.clock()-s
由于时间复杂度为O(M*M*N*N),因此当矩阵为100*100时,非常慢
因此还有一种手段,即枚举上下间所有的可能,共N*N种,对每一种使用 MaxSubArray,O(M),共计O(M*N*N)时间复杂度
如下所示:(图片来自编程之美)只需要一维算法嵌入二维算法中即可!
实际过程中,选择较小的维度,进行枚举,使得总复杂度降维 O(M*N*min(M,N))