算法题——矩阵的最大连续子序列和

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)

测试用例可以自己写一下。

当然也可以程序生成文件,由程序读取。

       

posted @ 2017-10-27 14:18  沐旧疆行  阅读(512)  评论(0编辑  收藏  举报