爱吃鱼饵

 

数据结构与算法之【最大子列和问题】

题目

【剑指offer】42.连续子数组的最大和

输入一个整型数组,数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。

示例1

输入: nums = [-2,1,-3,4,-1,2,1,-5,4]
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。

思路1:暴力破解法,将所有的子列和都列举出来。

class Solution:
    def maxSubArray(self, nums):  # 暴力求解
        '''
        :param nums: list
        :return: 最大子序列和
        '''
        assert isinstance(nums, list), "nums不是一个list"

        l = len(listA)
        MaxSum = 0
        for i in range(l):  # 子序列左段
            TheSum = 0
            for j in range(i, l):  # 子序列右端
                TheSum += nums[j]
                if TheSum > MaxSum:
                    MaxSum = TheSum
        return MaxSum

思路2:分而治之。“分”就是将大问题转化为小问题,“治”就是统一起来。算法思路:

  • 情况1:子列和最大值出现在子序列的左段;
  • 情况2: 子列和最大值出现在子序列的右端;
  • 情况3:子列和最大值出现在横跨两端的子列中;
def maxSubArray2(self, nums, left=0, right=0):  # 分而治之
    '''
    :param nums: list
    :param left: 求最大子列的起始下标
    :param right: 终止下标
    :return: 最大子序列和
    '''

    assert isinstance(nums, list), "nums不是一个list"
    assert left <= right, "输入错误,left>right"

    s = 0
    midSum = 0
    leftSum = 0
    rightSum = 0
    if left == right:
        s = nums[left]
    else:
        center = (left + right) // 2
        # print("center",center)
        leftSum = self.maxSubArray2(nums, left, center)  # 情况1 最大字段和全部取左边元素
        rightSum = self.maxSubArray2(nums, center + 1, right)  # 情况2 最大字段和全部取右边元素
        s1 = 0;
        lefts = 0  # 求出s1, 从中间到左边的最大和
        for i in range(center, left - 1, -1):
            lefts += nums[i]
            if s1 < lefts:
                s1 = lefts
        # print("s1:", s1)
        s2 = 0
        rights = 0  # 求出s2, 从中间到右边的最大和
        for i in range(center + 1, right, 1):
            rights += nums[i]
            if s2 < rights:
                s2 = rights
        # print("s2:", s2)
        midSum = s1 + s2  # 横跨中间的最大子段和
        s = max([midSum, leftSum, rightSum])

思路3:在线处理。优势在于对于任意的输入的子序列,都可以直接输出当前的最大子列和;重点在于当前的子列和能不能对后续的输入有作用,如果为最大子列和为负数则归零,如果加入新的值后当前子列和更大则更新最大子列和的值。

class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        '''
        :param nums: list
        :return: 最大子序列和
        '''
        l = len(nums)
        maxSum = nums[0]
        ThisSum = 0
        for i in range(l):
            ThisSum += nums[i]
            if ThisSum > maxSum: # 如果当前子列和更大,则更新masSum
                maxSum = ThisSum
            if ThisSum < 0: # 如果当前子列和<0,则必然不包括再最大子列和中
                ThisSum = 0
        return maxSum

提高:除了输出最大子列和以外,还要输出该最大子列的起始值和终了值。如果最大子序列不是唯一的,则输出索引i和j最小的子序列(如示例所示)。 如果所有K个数字均为负,则其最大和定义为0,并且应该输出整个序列的第一个和最后一个数字。

def maxSubarray3(self, nums):  # 在线处理
    '''
    :param nums: list
    :return: 最大子序列和
    '''
    l = len(nums)
    maxSum = -1
    ThisSum = 0
    left_index, right_index, temp_index = 0, l - 1, 0  # 初始化很重要,对于需要返回下标的时候
    for i in range(l):
        ThisSum += nums[i]
        if ThisSum < 0:
            ThisSum = 0
            temp_index = i + 1
        elif ThisSum > maxSum:
            maxSum = ThisSum
            left_index = temp_index
            right_index = i
    if maxSum < 0:  maxSum = 0
    return maxSum, left_index, right_index

posted on 2020-10-07 14:13  爱吃鱼饵  阅读(109)  评论(0编辑  收藏  举报

导航