import time ''' 输入一个整形数组,数组里可以有正数或负数。 数组中连续的一个或多个整数组成一个子数组, 每个子数组都有一个和。 求所有子数组的和的最大值。要求时间复杂度为O(n)。 例如输入的数组为1, -2, 3, 10, -4, 7, 2, -5,和最大的子数组为 3, 10, -4, 7, 2,因此输出为该子数组的和18。 现在需要输入一个整形的二维数组, 二维数组有横,竖,左斜线,右斜线四种数组集合。 求所有子数组的和的最大值,及最大值的数组长度,起始坐标及方向。(不考虑多个答案) 例如, 1 1 1 1 1 15 1 3 1 这个二维数组的答案是: 最大值是 18 , 起始坐标是 matrix[1][2] , 最大值的数组长度是2 方向是左下 1 1 1 1 2 1 1 3 1 这个二维数组的答案是: 最大值是 6 , 起始坐标是 matrix[0][1] , 最大值的数组长度是3 方向是下 ''' class MatrixMaxSumPart2: def __init__(self): pass def ininData(self): with open('D:/matrix.txt', 'r') as f: i = 0 j = 0 matrix = [[] for j in range(1024)] for line in f.readlines(): list = line.split() for size in range(len(list)): num = list[size] matrix[i].append(int(num)) i += 1 matrix = [[1, 1, 1], [1, 1, 15], [1, 3, 1]] return matrix def maxSum(self, matrix): maxNum = sumNum = 0 zuobiaoI = zuobiaoJ = changdu = 0 fangxiang = '' matrixlength = len(matrix) for i in range(matrixlength): # 获取横向的每一排 hengpai = matrix[i] hengpaiResult = self.maxSumLine(hengpai) if hengpaiResult[0] > maxNum: maxNum = hengpaiResult[0] zuobiaoI = i zuobiaoJ = hengpaiResult[1] changdu = hengpaiResult[2] fangxiang = '向右' # 获取竖向的每一排(正方形) shupai = [] for j in range(matrixlength): shupai.append(matrix[j][i]) shupaiResult = self.maxSumLine(shupai) if shupaiResult[0] > maxNum: maxNum = shupaiResult[0] zuobiaoI = shupaiResult[1] zuobiaoJ = i changdu = shupaiResult[2] fangxiang = '向下' # for i in range(len(matrix)): # 获取第一行每一个值(便于分析) # zhi1 = matrix[0][i] # 通过其为起点,可以获取1条右下的线 youxiaxian1 = [] # 直接用try,超出范围使用break for j in range(matrixlength): try: youxiaxian1.append(matrix[0 + j][i + j]) except Exception: break youxiaResult1 = self.maxSumLine(youxiaxian1) if youxiaResult1[0] > maxNum: maxNum = youxiaResult1[0] zuobiaoI = youxiaResult1[1] zuobiaoJ = i + youxiaResult1[1] changdu = youxiaResult1[2] fangxiang = '右下' # 获取第一列每一个值,便于分析 # zhi2 = matrix[i][0] # 通过其为起点,可以获取1条右下的线 youxiaxian2 = [] # 直接用try,超出范围使用break for j in range(matrixlength): try: youxiaxian2.append(matrix[i + j][j]) except Exception: break youxiaResult2 = self.maxSumLine(youxiaxian2) if youxiaResult2[0] > maxNum: maxNum = youxiaResult2[0] zuobiaoI = youxiaResult2[1] + i zuobiaoJ = youxiaResult2[1] changdu = youxiaResult2[2] fangxiang = '右下' # 获取第一行每一个值(便于分析) zhi1 = matrix[0][i] # 通过其为起点,可以获取1条左下的线 zuoxiaxian1 = [] # 直接用try,超出范围使用break for j in range(matrixlength): try: if (i - j) < 0: break zuoxiaxian1.append(matrix[0 + j][i - j]) except Exception: break zuoxiaResult1 = self.maxSumLine(zuoxiaxian1) if zuoxiaResult1[0] > maxNum: maxNum = zuoxiaResult1[0] zuobiaoI = zuoxiaResult1[1] zuobiaoJ = i - zuoxiaResult1[1] changdu = zuoxiaResult1[2] fangxiang = '左下' # 获取最后一列每一个值,便于分析 zuoxialength2 = matrixlength - 1 zhi2 = matrix[i][zuoxialength2] # 通过其为起点,可以获取1条左下的线 zuoxiaxian2 = [] # 直接用try,超出范围使用break for j in range(matrixlength): try: if (zuoxialength2 - j) < 0: break zuoxiaxian2.append(matrix[i + j][zuoxialength2 - j]) except Exception: break zuoxiaResult2 = self.maxSumLine(zuoxiaxian2) if zuoxiaResult2[0] > maxNum: maxNum = zuoxiaResult2[0] zuobiaoI = i + zuoxiaResult2[1] zuobiaoJ = zuoxialength2 - zuoxiaResult2[1] changdu = zuoxiaResult2[2] fangxiang = '左下' result = [] result.append(maxNum) result.append(zuobiaoI) result.append(zuobiaoJ) result.append(changdu) result.append(fangxiang) return result def maxSumLine(self, array): length = len(array) maxNum = sumNum = 0 zuobiaoI = changdu = 0 result = [] changdunew = zuobiaoInew = 0 # 首先卡线,即起始的i对应的值是负数,前面累计的值已经是负数了,则不再向下计算了。 # 对于长度,声明两个长度,一个是变化的,一个是返回值 # 变化的长度,每次遇到累计的值为负数,则清零一次,或者说每次后面的可能是最大的数,就重新计算一次。 # 只有在当前的累计数确实超过了最大值时,变化的长度变成有效的,赋值给返回值。 # 对于坐标。声明两个坐标,一个是变化的,一个是返回值。 # 坐标计算稍微简单,遇到累计的值是负数时,变化的坐标清空为-1, -1也作为重新开始的标识(0作为重新开始会忽略掉第一个点)。 # 而只有变化的坐标是重新开始的时候,才能被赋值,赋值的时机只有一次,即第一次起始的值大于等于0的时候。 # 而同样,只有在这次的累计值大于最大值时,变化的坐标才有效,才赋值给返回值。 # 存在变化的长度和变化的坐标的原因,是因为它们可能被清空,而返回值是不能被清空的 for i in range(length): if sumNum == 0 and array[i] < 0: changdunew = 0 zuobiaoInew = -1 continue sumNum += array[i] if sumNum >= 0: changdunew += 1 if zuobiaoInew == -1: zuobiaoInew = i if sumNum < 0: sumNum = 0 changdunew = 0 zuobiaoInew = -1 if sumNum > maxNum: maxNum = sumNum changdu = changdunew zuobiaoI = zuobiaoInew result.append(maxNum) result.append(zuobiaoI) result.append(changdu) return result if __name__ == '__main__': # list = [-2,-3,2, 3, -3, 4, -6, -1, 6] # result = MatrixMaxSumPart2().maxSumLine(list) # print("maxsum is", result) data = MatrixMaxSumPart2().ininData() start = int(round(time.time() * 1000)) print(MatrixMaxSumPart2().maxSum(data)) end = int(round(time.time() * 1000)) print(end - start)
本身是一道比较繁琐的算法题,没有好的递归方法,是需要纯编码计算的。
如果单纯求矩阵的最大子序列和,还凑合,但是又增加了起始坐标,长度后,题目对编码思维的要求就比较多了。
题目至少有两种解法:
1. 对每一个点做一次计算,每一个点都有可能是起点。
优化的点包括,如果起点是负数,则跳过。方向可以只包含右,下,右下,左下四个。如果累次相加为负数,则跳过。
2. 对每一行做一次计算(上面的代码,比较快)
其主要优化的点是每一行如何计算最大子序列,难点是如何计算坐标,及长度。
解法1代码我也实现了,如下:
1 import time 2 3 4 class MatrixMaxSum: 5 def __init__(self): 6 pass 7 8 def ininData(self): 9 with open('D:/matrix.txt', 'r') as f: 10 i = 0 11 j = 0 12 matrix = [[] for j in range(1024)] 13 for line in f.readlines(): 14 list = line.split() 15 for size in range(len(list)): 16 num = list[size] 17 matrix[i].append(int(num)) 18 i += 1 19 # matrix = [[1, 4, 9], [7, 6, 3], [4, 8, 4]] 20 return matrix 21 22 def maxSum(self, matrix): 23 maxNum = sumNum = 0 24 zuobiaoI = zuobiaoJ = changdu = 0 25 fangxiang = '' 26 for i in range(len(matrix)): 27 matrixIlength = len(matrix[i]) 28 for j in range(matrixIlength): 29 # 下标是[i][j] 30 num = matrix[i][j] 31 # 如果本身是负数,则跳过 32 if num < 0: 33 continue; 34 35 sumNum = 0 36 changduA = 0 37 # 向右前进 38 for right in range(matrixIlength - j): 39 rightNum = matrix[i][j + right] 40 sumNum += rightNum 41 changduA += 1 42 if sumNum < 0: 43 sumNum = 0 44 changduA = 0 45 break 46 elif sumNum > maxNum: 47 maxNum = sumNum 48 zuobiaoI = i 49 zuobiaoJ = j 50 changdu = changduA 51 fangxiang = '右' 52 53 sumNum = 0 54 changduA = 0 55 # 向下前进 56 for down in range(matrixIlength - i): 57 downNum = matrix[i + down][j] 58 sumNum += downNum 59 changduA += 1 60 if sumNum < 0: 61 sumNum = 0 62 changduA = 0 63 break 64 elif sumNum > maxNum: 65 maxNum = sumNum 66 zuobiaoI = i 67 zuobiaoJ = j 68 changdu = changduA 69 fangxiang = '下' 70 71 sumNum = 0 72 changduA = 0 73 # 向右下前进(由于是正方形) 74 if i < j: 75 indexRightDown = j 76 else: 77 indexRightDown = i 78 for rightdwon in range(matrixIlength - indexRightDown): 79 rightdwonNum = matrix[i + rightdwon][j + rightdwon] 80 sumNum += rightdwonNum 81 changduA += 1 82 if sumNum < 0: 83 sumNum = 0 84 changduA = 0 85 break 86 elif sumNum > maxNum: 87 maxNum = sumNum 88 zuobiaoI = i 89 zuobiaoJ = j 90 changdu = changduA 91 fangxiang = '右下' 92 93 sumNum = 0 94 changduA = 0 95 # 向左下前进(由于是正方形) 96 # if i < j: 97 # indexRightDown = i 98 # else: 99 # indexRightDown = j 100 for leftdown in range(matrixIlength): 101 iIndex = i + leftdown 102 jIndex = j - leftdown 103 try: 104 leftdownNum = matrix[i + leftdown][j - leftdown] 105 except Exception as e: 106 break 107 sumNum += leftdownNum 108 changduA += 1 109 if sumNum < 0: 110 sumNum = 0 111 changduA = 0 112 break 113 elif sumNum > maxNum: 114 maxNum = sumNum 115 zuobiaoI = i 116 zuobiaoJ = j 117 changdu = changduA 118 fangxiang = '左下' 119 120 result = [] 121 result.append(maxNum) 122 result.append(zuobiaoI) 123 result.append(zuobiaoJ) 124 result.append(changdu) 125 result.append(fangxiang) 126 127 return result 128 129 130 if __name__ == '__main__': 131 data = MatrixMaxSum().ininData() 132 start = int(round(time.time() * 1000)) 133 print(MatrixMaxSum().maxSum(data)) 134 end = int(round(time.time() * 1000)) 135 print(end - start)
测试用例可以自己写一下。
当然也可以程序生成文件,由程序读取。