LeetCode 1191 K 次串联后最大子数组之和——kadane算法首次学习

题目:

给你一个整数数组 arr 和一个整数 k。首先,我们要对该数组进行修改,即把原数组 arr 重复 k 次。

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

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

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

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/k-concatenation-maximum-sum

首先是解题的算法kadane算法的学习:

滴滴面试手撕算法题-kadane算法 - 知乎(很不错的参考文章)

重要思路是计算最大子数组时,不能以某个节点为开头来寻找,要以某个节点为结束来寻找,这样下次的寻找可以利用上一次寻找的结果,典型的动态规划了,第二个关键点是将子问题定义为求以i为终止下标的子数组之和的最大值。这样就有了基础算法

def maxSubArrayDP(nums):
    length = len(nums)
    dp = [0 for i in range(length)]
    dp[0] = nums[0]
    for i in range(1, length):
        dp[i] = max(dp[i-1]+nums[i], nums[i])
    return max(dp)

kadane算法是在动态规划解的基础上进一步优化。它使用一根指针保存以i为结尾的子数组最大值之和,使用另一根指针保存迄今为止的子数组最大值之和。因为每一次只需要用到前一次结果,无需全部储存

def maxSubArrayKadane(nums):
    length = len(nums)
    max_ending_here = max_plus_sum = nums[0]
    for i in range(1,length):
        max_ending_here = max(max_ending_here+nums[i],nums[i])
        max_plus_sum = max(max_ending_here, max_plus_sum)
    return max_plus_sum

下面就是题目的答案:

class Solution:
    def kConcatenationMaxSum(self, arr: List[int], k: int) -> int:
        #在一开始进行简单判断,对特殊情况有奇效
        if (max(arr) <= 0): return 0
        if (min(arr) >= 0): return sum(arr)*k % (10**9 + 7)
        #这里记录前缀和以及后缀和为了后面计算
        maxpresum = presum = arr[0]
        maxaftsum = aftsum = arr[-1]
        maxsum = maxend = arr[0]
        length = len(arr)
        for i in range(1, length):
            presum += arr[i]
            maxpresum = max(presum, maxpresum)
            aftsum += arr[-i - 1]
            maxaftsum = max(aftsum, maxaftsum)
            #kadane算法
            maxend = max(maxend + arr[i], arr[i])
            maxsum = max(maxsum, maxend)
        #讨论k的范围
        if k == 1: return maxsum % (10**9 + 7)
        #q1
        arrsum = sum(arr)
        if arrsum > 0:
            return max(maxsum + (k-1) * arrsum, maxaftsum + maxpresum) % (10**9 + 7)
        else:
            return max(maxsum, maxaftsum + maxpresum) % (10**9 + 7)

这里要注意注释q1处,若数组和大于0,要比较是一轮的结果加上后面所有的大还是取两轮数组中间的某一段大,前者直接就是一轮的结果 +(轮数 - 1)* 数组的和,后者可以表示为最大前缀和+最大后缀后,这点比较难想到,若数组和小于0,直接比较第一轮结果和最大前缀和+最大后缀和

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值