题目
【剑指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