题目:
给你一个整数数组 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,直接比较第一轮结果和最大前缀和+最大后缀和