5月挑战Day15-Maximum Sum Circular Subarray(Medium)

Day15-Maximum Sum Circular Subarray(Medium)

问题描述:

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.)

从一个环形数组找到和最大的子数组。所谓环形数组就是【2,1,3】,遍历到最后一个位置3时还可以回到开始位置继续走即【2,1,3,2,1,3】,但是这个环形数组题目中有要求,我们不能循环超过两次以上,也就是同一个‘数’不能出现两次在子数组中,就是【2,1,3,2】这就不可以,因为2这个数字出现了两次,而【1,3,2】就是可以了。换句话说我们形成的子数组的长度不能超过原数组的长度(超过了肯定就包含两个重复的数字了)。

Example:

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

解法一(暴力解法,没通过。。):

既然子数组的长度不能超过原数组的长度,那么我们就从头开始遍历数组,每遍历一个位置就把当前位置能形成的各种子数组的和都求一遍找最大值,然后我们把当前位置移到数组的末尾(便于数组求和)。

class Solution:
    def maxSubarraySumCircular(self, A: List[int]) -> int:
        ##暴力破解来一波:
##形成的子数组的长度不能超过现有的数组的长度,也就是最大的长度就是先有数组的长度
##那么我们从第一个位置开始的话,现有的最大长度和就是这个数组的和,然后依次减少长度
##然后移到第二个位置,。。。
        result = A[0]
        for i in range(len(A)):
            for j in range(len(A),0,-1):
                temp = sum(A[0:j])
                if result < temp:
                    result = temp
            A = A[1:] + [A[0]]
        return result

时间复杂度为O(n*n),这是不包含里面那个求和函数的复杂度(因为不知道python内置的sum()的复杂度(懒得查了。。))。时间复杂度巨大,肯定通过不了啊,这要能通过这道题也就不是中等难度的题了。

解法二:

正解应该就是用Kadanes algorithm,这个算法之前有道求子数组和的题用过,当时没在意,导致这道题看了好多博客才看懂。。。
应该属于动态规划的算法吧。
这道题有两种情况的解:
1.最大的子数组在数组里面,即没有跨数组(没有头尾相连的情况。)这种就是普通的数组中子数组的求解,用这个算法,设置一个局部最大值和全局最大值,每次遍历一个元素,更新这个局部最大值和全局最大值,说一下局部最大值的更新方法就是,前一个位置的局部最大值加上当前值和当前值的比较,返回最大值。
2.第二种情况就是跨越了两个数组,这时我们可以用整个数组的和减去中间部分的最小值的和,而这个最小子数组的求法跟上面那个类似。
最后我们返回两种情况的最大值就可以了,有一点值得注意的情况就是数组全为负数时,这时全局最小和数组的和相等,两者相减为0,而全局最大反而是个负数,这就不合理了,所以我们单独if一下这种情况。

class Solution:
    def maxSubarraySumCircular(self, A: List[int]) -> int:
        local_min,local_max = 0,0
        global_min,global_max = float('inf'),float('-inf')
        for i in A:

            local_min = min(i,i + local_min)
            global_min = min(global_min,local_min)
            local_max = max(i,i + local_max)
            global_max = max(global_max,local_max)
        
        if sum(A) == global_min:
            return global_max
        else:
            return max(global_max,sum(A) - global_min)

时间复杂度为O(N),这道题看了挺多的博客解释的,然后感觉自己解释的有点乱(因为每天都是晚上写博客,没啥精力了,所以写的比较急。。。)贴一下那些大神的关于这题的解释,很清楚了,有的还贴了图解释。

Grandyang
Leetcode 918 Maximum Sum Circular Subarray
滴滴面试手撕算法题-kadane算法
Python O(n) by Kadane algorithm 80%+ [w/ Visualization]

你可能感兴趣的:(5月挑战Day15-Maximum Sum Circular Subarray(Medium))