1. 程式人生 > >Leetcode 53:最大子序和(最詳細的解法!!!)

Leetcode 53:最大子序和(最詳細的解法!!!)

給定一個整數陣列 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演算法。通過這個演算法我們可以很簡單的找到子陣列的最大和。我們初始化兩個變數resultcur,分別表示最後的最大值和當前的最大值。演算法思路如下

  • 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:

如有問題,希望大家指出!!!