資料結構與演算法之【最大子列和問題】
阿新 • • 發佈:2020-10-07
題目
【劍指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