题目理解
小包收到了 N 个甜点,每个甜点有一个喜爱值。这些甜点被连续送来了 M 次,形成了一个长度为 N×M 的甜点序列。我们需要从这个序列中找到一段连续的甜点,使得这段甜点的总喜爱值最大化。
解题思路
-
单个数组的最大子数组和:
- 首先,我们需要计算单个数组(即一次送来的 N 个甜点)的最大子数组和。这可以通过经典的 Kadane 算法来实现。
-
跨数组的最大子数组和:
-
如果 M>1,我们需要考虑跨数组的情况。具体来说,我们需要计算:
- 前缀和的最大值:即从数组开头到某个位置的最大子数组和。
- 后缀和的最大值:即从数组某个位置到结尾的最大子数组和。
-
如果整个数组的总和是正数,那么跨数组的最大子数组和可以通过前缀和的最大值、后缀和的最大值以及中间部分的和(即 (M−2)×total_sum)来计算。
-
如果整个数组的总和是负数,那么跨数组的最大子数组和就是前缀和的最大值加上后缀和的最大值。
-
-
综合考虑:
- 最终的最大子数组和应该是单个数组的最大子数组和与跨数组的最大子数组和中的较大值。
数据结构与算法步骤
-
Kadane 算法:
- 用于计算单个数组的最大子数组和。
-
前缀和与后缀和:
- 用于计算跨数组的最大子数组和。
-
综合比较:
- 比较单个数组的最大子数组和与跨数组的最大子数组和,取较大值作为最终结果。
复杂度分析
- 时间复杂度:O(N),其中 N 是每次送来的甜点数量。
- 空间复杂度:O(1),只需要常数空间来存储中间结果。
参考代码
def solution(N, M, data):
# 计算单个数组的最大子数组和
def max_subarray_sum(arr):
max_ending_here = max_so_far = arr[0]
for x in arr[1:]:
max_ending_here = max(x, max_ending_here + x)
max_so_far = max(max_so_far, max_ending_here)
return max_so_far
# 计算整个数组的最大子数组和
max_single_array = max_subarray_sum(data)
# 计算整个数组的总和
total_sum = sum(data)
# 计算跨数组的最大子数组和
if M > 1:
max_prefix_sum = float('-inf')
max_suffix_sum = float('-inf')
current_prefix_sum = 0
current_suffix_sum = 0
for i in range(N):
current_prefix_sum += data[i]
max_prefix_sum = max(max_prefix_sum, current_prefix_sum)
for i in range(N-1, -1, -1):
current_suffix_sum += data[i]
max_suffix_sum = max(max_suffix_sum, current_suffix_sum)
# 修正跨数组的最大子数组和计算
if total_sum > 0:
max_combined_sum = max(max_single_array, max_prefix_sum + max_suffix_sum + (M-2) * total_sum)
else:
max_combined_sum = max(max_single_array, max_prefix_sum + max_suffix_sum)
else:
max_combined_sum = max_single_array
return max_combined_sum