Leetcode 53:最大子序和(最詳細的解法!!!)
阿新 • • 發佈:2018-12-14
給定一個整數陣列 nums
,找到一個具有最大和的連續子陣列(子陣列最少包含一個元素),返回其最大和。
示例:
輸入: [-2,1,-3,4,-1,2,1,-5,4],
輸出: 6
解釋: 連續子陣列 [4,-1,2,1] 的和最大,為 6。
進階:
如果你已經實現複雜度為 O(n) 的解法,嘗試使用更為精妙的分治法求解。
解題思路
這個問題通過遞迴可以很快速的解決。我們要知道[0:i]
這個區間內的最大值cur
,那麼我們只需要知道[0:i-1]
這個區間內的最大值pre
,那麼cur=max(pre+nums[i], nums[i])
。很多人這個會疑惑為什麼pre
不參與比較,這是因為我們的定義cur
[0:i]
這個區間內的最大值,實際上裡面隱藏了包含num[i]
這個細節(為什麼?)。
然後下面這段邏輯就順理成章了
class Solution:
def maxSubArray(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
self.result = nums[0]
self._maxSubArray(nums, len(nums) - 1)
return self.result
def _maxSubArray (self, nums, index):
if index == 0:
return nums[0]
pre = self._maxSubArray(nums, index - 1)
cur = max(pre + nums[index], nums[index])
self.result = max(self.result, cur)
return cur
我們同樣可以通過記憶化搜尋的方法來優化上面這個問題,這裡我不再贅述。我們看看怎麼通過動態規劃來求解這個問題。實際上狀態方程就是上面程式碼中的那三行
class Solution:
def maxSubArray(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
pre, cur = 0, float('-inf')
for num in nums:
pre += num
cur = max(cur, pre)
if pre < 0:
pre = 0
return cur
我們可以將狀態方程歸納為
cur = max(cur, pre + num) if pre > 0
實際上上面這種寫法還有一個更為簡潔的表示
class Solution:
def maxSubArray(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
for i in range(1, len(nums)):
if nums[i-1] > 0:
nums[i] += nums[i-1]
return max(nums)
解決這個問題,還有一個經典的演算法,就是Kadane
演算法。通過這個演算法我們可以很簡單的找到子陣列的最大和。我們初始化兩個變數result
和cur
,分別表示最後的最大值和當前的最大值。演算法思路如下
cur = cur + num (for num in nums)
cur = 0 if cur < 0
result = cur if cur > result
程式碼如下
class Solution:
def maxSubArray(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
result, cur = float('-inf'), 0
for num in A:
cur += num
cur = max(cur, 0)
result = max(result, cur)
return result
實際上也可以將1,2
順序換一下,但是要注意初始條件的變化。
class Solution:
def maxSubArray(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
result = cur = float('-inf')
for num in nums:
cur = max(cur, 0) + num
result = max(result, cur)
return result
至於提高中所說的分治策略,我覺得在這裡其實沒有必要了。
reference:
如有問題,希望大家指出!!!