1. 程式人生 > >Leetcode 918:環形子陣列的最大和(最詳細的解法!!!)

Leetcode 918:環形子陣列的最大和(最詳細的解法!!!)

給定一個由整數陣列 A 表示的環形陣列 C,求 C的非空子陣列的最大可能和。

在此處,環形陣列意味著陣列的末端將會與開頭相連呈環狀。(形式上,當0 <= i < A.lengthC[i] = A[i],而當 i >= 0C[i+A.length] = C[i]

此外,子陣列最多隻能包含固定緩衝區 A 中的每個元素一次。(形式上,對於子陣列 C[i], C[i+1], ..., C[j],不存在 i <= k1, k2 <= j 其中 k1 % A.length = k2 % A.length

示例 1:

輸入:[1,-2,3,-2]
輸出:3
解釋:從子陣列 [3] 得到最大和 3

示例 2:

輸入:[5,-3,5]
輸出:10
解釋:從子陣列 [5,5] 得到最大和 5 + 5 = 10

示例 3:

輸入:[3,-1,2,-1]
輸出:4
解釋:從子陣列 [2,-1,3] 得到最大和 2 + (-1) + 3 = 4

示例 4:

輸入:[3,-2,2,-3]
輸出:3
解釋:從子陣列 [3] 和 [3,-2,2] 都可以得到最大和 3

示例 5:

輸入:[-2,-3,-1]
輸出:-1
解釋:從子陣列 [-1] 得到最大和 -1

提示:

  1. -30000 <= A[i] <= 30000
  2. 1 <= A.length <= 30000

解題思路

對於這個環形陣列問題,我們會出現這樣的兩種情況不包含迴圈節點的子陣列和包含迴圈節點(首尾節點)的子陣列。對於不包含迴圈節點的子陣列,我們直接使用Kadane

演算法即可。而對於包含迴圈節點的子陣列,我們只要將nums中的每個元素取相反數,然後對這個相反數陣列-nums運用Kandane演算法就可以求解出Kadane(-nums.subset)(一定不包含迴圈節點,為什麼?原來的最大變為了現在的最小,此時求解出來的實際上是原來最小值的相反數),然後我們將sum(nums)+Kadane(-nums.subset)就可以得到有迴圈節點的最大值。圖示

但是這個思想有一個小bug,當我們最後求得的最大值是由整個陣列構成的話,那麼這個問題就回到了第一個問題(不包含迴圈節點)。舉這樣的例子

-1, -2, -3

驗算一下就會發現不合理的地方。這種情況也很好剔除,只要在程式的初始階段檢查一下max(nums)

是不是小於零即可。

class Solution:
    def maxSubarraySumCircular(self, A):
        """
        :type A: List[int]
        :rtype: int
        """
        def kadane(nums):
            result = cur = float('-inf')
            for num in nums:
                cur = max(cur, 0) + num
                result = max(result, cur)
            return result

        max_A = max(A)
        if max_A < 0:
            return max_A

        result1 = kadane(A)
        result2 = sum(A) + kadane([-num for num in A])
        return max(result1, result2)

非常簡潔,非常優雅!!!

實際上我們可以將kadane演算法嵌入到現在的演算法中,而不是單獨處理,這樣我們又得到了一個更加簡潔的程式碼。

class Solution:
    def maxSubarraySumCircular(self, A):
        """
        :type A: List[int]
        :rtype: int
        """
        total, maxSum, curMax, minSum, curMin = 0, float('-inf'), 0, float('inf'), 0
        for a in A:
            curMax = max(curMax + a, a)
            maxSum = max(maxSum, curMax)
            curMin = min(curMin + a, a)
            minSum = min(minSum, curMin)
            total += a
        return max(maxSum, total - minSum) if maxSum > 0 else maxSum

真的是非常棒!!!

reference:

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