Leetcode May Challenge - 05/15: Maximum Sum Circular Subarray(Python)

题目描述

Given a circular array C of integers represented by A, find the maximum possible sum of a non-empty subarray of C.

Here, a circular array means the end of the array connects to the beginning of the array. ** (Formally, C[i] = A[i] when 0 <= i < A.length, and C[i+A.length] = C[i] when i >= 0.)**

Also, a subarray may only include each element of the fixed buffer A at most once. (Formally, for a subarray C[i], C[i+1], …, C[j], there does not exist i <= k1, k2 <= j with k1 % A.length = k2 % A.length.)

例子

Example 1:

Input: [1,-2,3,-2]
Output: 3
Explanation: Subarray [3] has maximum sum 3

Example 2:

Input: [5,-3,5]
Output: 10
Explanation: Subarray [5,5] has maximum sum 5 + 5 = 10

Example 3:

Input: [3,-1,2,-1]
Output: 4
Explanation: Subarray [2,-1,3] has maximum sum 2 + (-1) + 3 = 4

Example 4:

Input: [3,-2,2,-3]
Output: 3
Explanation: Subarray [3] and [3,-2,2] both have maximum sum 3

Example 5:

Input: [-2,-3,-1]
Output: -1
Explanation: Subarray [-1] has maximum sum -1

解释

这道题的题干比较绕。简单来说就是给一个环状数组的pattern,记作A。这个pattern的意思就是,整个数组是这个pattern的无限次循环。比如pattern是[1, 2],那整个数组就是[1, 2, 1, 2, 1, 2…]。现在我们要找到一个subarray,让subarray的每个元素的加和最大。这个subarray要满足一个条件:在一个pattern中相同位置的元素只能用一次。比如[5, -3, 5],最大的subarray的和是10([5, 5]),而没有更大的组合比如[5, -3, 5, 5]。这是因为后者的第一个5和第二个5都是pattern中的第一个元素(只不过是在环状数组中的相邻两个pattern中)。

思路 Kadane算法(DP)

维护一个和pattern A长度相同的数组,数组的每一个位置记录到当前元素为止,含当前元素的子串的最大和。这个是DP的一个经典应用。举个例子:对第一个元素来说,含当前元素的子串的最大和一定是自己,因为没有别的元素可以组合了。所以dp[0] = A[0]。对于第二个元素来说,有两种可能性:第一种是当前元素自己,第二种是当前元素加上到当前元素上一个元素的最大子串和。而这个字串和恰好就是dp[i - 1]。所以dp[i] = max(A[i], A[i] + dp[i - 1])。以此类推。这是第一种情况。
但这道题的特殊之处在于,你找到了对pattern的最大和子串,未必是最终结果,因为目标子串可能跨过了右边界。这是第二种情况。而如果跨过了右边界,我们可以想想,这种情况下的最大子串如果放在一个pattern中来说,就是一个pattern中抠掉了中间的某一些元素,使结果最大。比如例子中的[5, -3, 5],答案可以理解为[5, -3, 5, 5, -3, 5],也可以理解为一个pattern[5, -3, 5]中把-3扣掉了。理解到这,我们就要考虑,抠掉哪些元素可以使剩下的和最大?答案就是找到一个pattern中和最小的字串。该目标正好与第一种情况相反。
因此,我们维护两个数组,一个找pattern中的max子串,另一个找pattern中的min子串。最后,我们把max子串中的最大值整个pattern的和减去min子串的最小值作比较,返回更大的那一个即可。

代码

class Solution(object):
    def maxSubarraySumCircular(self, A):
        """
        :type A: List[int]
        :rtype: int
        """
        if not A:
            return 0
        dp_max = [-99999] * len(A)
        dp_min = [-99999] * len(A)
        dp_max[0], dp_min[0] = A[0], A[0]
        for i in range(1, len(A)):
            dp_max[i] = max(A[i], dp_max[i - 1] + A[i])
            dp_min[i] = min(A[i], dp_min[i - 1] + A[i])
        
        if min(dp_min) == sum(A):
            return max(dp_max)
        else:
            return max(max(dp_max), sum(A) - min(dp_min))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值