LeetCode-Python-1191. K 次串联后最大子数组之和

648 篇文章 23 订阅

给你一个整数数组 arr 和一个整数 k

首先,我们要对该数组进行修改,即把原数组 arr 重复 k 次。

举个例子,如果 arr = [1, 2] 且 k = 3,那么修改后的数组就是 [1, 2, 1, 2, 1, 2]

然后,请你返回修改后的数组中的最大的子数组之和。

注意,子数组长度可以是 0,在这种情况下它的总和也是 0

由于 结果可能会很大,所以需要 模(mod) 10^9 + 7 后再返回。 

 

示例 1:

输入:arr = [1,2], k = 3
输出:9

示例 2:

输入:arr = [1,-2,1], k = 5
输出:2

示例 3:

输入:arr = [-1,-2], k = 7
输出:0

 

提示:

  • 1 <= arr.length <= 10^5
  • 1 <= k <= 10^5
  • -10^4 <= arr[i] <= 10^4

思路:

直接把 k 个 arr 连在一起然后找答案显然不现实……

先把简单的情况讨论一下,

1. 如果arr里所有数字都比0小,那么很简单,一个数字都不应该选,直接返回0

2. 如果arr里所有数字都比0大,那么也很简单,直接把所有数字都选上,返回 sum(arr) * k

从2推广一下,如果sum(arr) > 0, 那么如何处理?

    现在有 k 个 arr, 已知sum(arr) > 0, 那么是不是每个arr全都选上就可以取到最大值了呢?

    分析一下可知,对于中间的(k - 2)的arr来说,每一个arr都应该全部选中,因为只要多选一个arr, 总和就一定会更大,

但是对于第一个arr, 和最后一个arr则不同,

第一个arr可能是这样的,[-5, 6, 7, 2], 此时我们需要判断从哪一个数开始,能得到最大的局部子数组和,因此可以利用后缀和数组产生[10, 15, 9, 2]这样的中间结果,第 i 位 代表从末尾到 arr[i] 之间的数字之和,中间数组的最大值就是最大局部子数组和,

最后一个arr则是同理,利用前缀和找最大局部子数组和。

对于sum(arr) <= 0 的这种情况,我们只需要在 arr + arr 的范围里用普通的dp算法找最大子数组和即可,

这是因为已知 sum(arr)非正数,那么每多加一个arr,只会让目前的数组和更小。

因此只需考虑arr + arr的情况,在普通的数组或循环数组里找一次即可。

class Solution(object):
    def kConcatenationMaxSum(self, arr, k):
        """
        :type arr: List[int]
        :type k: int
        :rtype: int
        """
        if max(arr) < 0:
            return 0
        if sum(arr) > 0:
            res = sum(arr) * (k - 2)
            dp = [0] * len(arr)
            dp[0] = arr[0]
            for i in range(1,len(arr)):
                dp[i] = dp[i - 1] + arr[i]
                    
            res += max(dp)
            dp = [0] * len(arr)
            dp[-1] = arr[-1]
            for i in range(len(arr) - 2, -1, -1):
                dp[i] = dp[i + 1] + arr[i]
                    
            res += max(dp)
            return (res)% (10 ** 9 + 7)
        
        arr = arr + arr
        dp = [0] * len(arr)
        dp[0] = arr[0]
        for i in range(1,len(arr)):
            if dp[i - 1] > 0:
                dp[i] = dp[i - 1] + arr[i]
            else:
                dp[i] = arr[i]
                
        return max(dp) % (10 ** 9 + 7)
        

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值