美文网首页
连续子数组的最大和

连续子数组的最大和

作者: leejnull | 来源:发表于2020-01-08 21:54 被阅读0次

例子说明

输入的数组为{1, -2, 3, 10, -4, 7, 2, -5},和最大的子数组为{3, 10, -4, 7, 2}。因此输出为该子数组的和18

我的第一想法

把所有的可能的子数组全部循环遍历出来,找出和最大的那个数据,记录,要用到双层循环

直接上代码

def cla(lyst):
    max_array = []
    max_sum = 0
    counter = 0
    for i in range(len(lyst)):
        for j in range(i+1, len(lyst)+1):
            sub_array = lyst[i:j]
            sub_sum = sum(sub_array)
            counter += 1
            if sub_sum > max_sum:
                max_array = sub_array
                max_sum = sub_sum
            elif sub_sum == max_sum:
                max_array.append(sub_array)
    print(max_array, max_sum)
    print(counter)


if __name__ == "__main__":
    cla([1, -2, 3, 10, -4, 7, 2, -5])

这种简单粗暴的方式耗费的时间是:

n+n-1+n-2+n-3+...+1 -> 1/2 * n^2 + 1/2 * n

时间复杂度应该是O(n^2)

第二次优化

思考一下这种规律,第一个数1,第二个数-2,和为-1,那么从外层循环1开始,内存循环在-2之后都是没有意义的了,因为前两个数的和为负数或0,和后面的数组成子数组的和肯定是比后面的数自己组成子数组更小或相等的,而在外层循环继续往后走的时候肯定也会碰到后续的子数组,即:[1, -2, 3]这样的子数组可以直接忽略,直接从[3]开始了

def cla(lyst):
    max_array = []
    max_sum = 0
    counter = 0
    for i in range(len(lyst)):
        for j in range(i+1, len(lyst)+1):
            sub_array = lyst[i:j]
            sub_sum = sum(sub_array)
            counter += 1
            if sub_sum <= 0:
                break;
            if sub_sum > max_sum:
                max_array = sub_array
                max_sum = sub_sum
            elif sub_sum == max_sum:
                max_array.append(sub_array)
    print(max_array, max_sum)
    print(counter)


if __name__ == "__main__":
    cla([1, -2, 3, 10, -4, 7, 2, -5])

第三次优化

这几天一直在看MOOC上浙江大学的数据结构讲课,讲到了这个问题。上面写的两个算法时间复杂度都是O(n2),当我们每次看到O(n2)这种类型的复杂度的时候,都要再思考是否可以优化成 nlog n。
采用分治法的思想,把数组每次分成两份,递归的分解,直到最后只有一个元素的时候,如果元素小于0就返回0,否则返回原值。分别计算中间点左右两边的最大和,同时还要考虑横跨中间点的和。

2019-07-03-01.png
# 分治法
# 算法复杂度:O(nlogn)
def cla(items, left, right):
    maxLeftSum = 0
    maxRightSum = 0
    leftBorderSum = 0
    rightBorderSum = 0
    maxLeftBorderSum = 0
    maxRightBorderSum = 0
    
    if left == right:
        if items[left] > 0:
            return items[left]
        else:
            return 0
    
    center = (left+right) // 2
    maxLeftSum = maxSubseqSum2(items, left, center)
    maxRightSum = maxSubseqSum2(items, center+1, right)

    # 左边最大和
    for i in range(center-1, left-1, -1):
        leftBorderSum += items[i]
        maxLeftBorderSum = max(leftBorderSum, maxLeftBorderSum)
    
    # 右边最大和
    for i in range(center, right+1):
        rightBorderSum += items[i]
        maxRightBorderSum = max(rightBorderSum, maxRightBorderSum)

    return max(maxLeftBorderSum+maxRightBorderSum, max(maxLeftSum, maxRightSum))

第四次优化

我觉得把我第二次优化的第二层循环去掉,在优化一下就是这个了,一直不明白贪心算法是什么意思,希望再接下来的学习中能理解。这样的话算法复杂度就降低到O(n)的水平了,nice啊~

# 贪心算法
# 算法复杂度:O(n)
def maxSubseqSum3(items):
    maxSum = tempSum = 0
    itemsLength = len(items)
    for i in range(0, itemsLength):
        tempSum += items[i]
        if tempSum > maxSum:
            maxSum = tempSum
        elif tempSum < 0:
            tempSum = 0
    print(maxSum)
    return maxSum

总结

当我们把一个算法复杂度修改到O(n^2)的时候,一定要再想想是不是能优化到 nlog n 的层次。

算法复杂度排名:n! > 2^n > n^3 > n^2 > nlog n > n > log n > 1

两段算法相加,复杂度 = 最大的算法复杂度
两段算法相乘,复杂度 = 两段算法复杂度相乘

来自 https://leejnull.github.io/2019/08/20/2019-07-03/

相关文章

  • 动态规划

    1子序列的最大和 给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最...

  • [剑指offer]刷题笔记

    连续子数组的最大和(常见✔) 最小的k个数 数组中出现次数超过一半的数字 数据流中的中位数(难♧) 连续子数组的最...

  • 连续子数组的最大和和子数组

    网上多见的是输出连续子数组的最大和,此代码还额外输出了最大和对应的子数组。代码如下:

  • 2022-02-26最大子数组的和

    给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。 子数组...

  • Swift刷算法:最大子数组和

    给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。子数组 ...

  • 53. 最大子序和

    题目链接: 53. 最大子序和 题目描述: 给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最...

  • 连续子数组最大和

    二刷: 剑指思路,只需要遍历一遍

  • 连续子数组最大和

    思路:

  • 连续子数组最大和

    方法1:归纳法 方法2:动态规划

  • 连续子数组最大和

    描述:输入一个整型数组,数组里有正数也有负数。数组中一个或连续的多个整数组成一个子数组。求所有子数组的和的最大值。...

网友评论

      本文标题:连续子数组的最大和

      本文链接:https://www.haomeiwen.com/subject/djheactx.html