贪心的小宝|豆包MarsCode AI 刷题

191 阅读6分钟

问题描述

小包非常喜欢吃甜点,他收到了一次性送来的 NN 个甜点,每个甜点都有一个对应的喜爱值。

但是这还不够!小包让小哥连续送来了 MM 次相同的 NN 个甜点,并将这些甜点首尾相接排成一排。

现在,小包面前有 (N×M)(N×M) 个排成一排的甜点,小包希望从中选择一段连续的甜点,使得这段甜点的总喜爱值最大化。

注意:尽管小包喜欢甜食,但有些甜点可能不合口味,导致其喜爱值为负数。小包至少要选择一个甜点来满足他对甜点的贪心。

输入参数

  • 整数 ( N ):表示每次送来的甜点数量。
  • 整数 ( M ):表示送来的次数。
  • 数组 data:长度为 ( N ),表示每个甜点的喜爱值。

返回结果

  • 一个整数,表示在 N×MN×M 个甜点中可以选择的连续甜点段的最大总喜爱值。

测试样例

样例1:

输入:N = 5 ,M = 1 ,data = [1, 3, -9, 2, 4]
输出:6
解释:选择甜点 [2, 4],最大总喜爱值为 6

样例2:

输入:N = 5 ,M = 3 ,data = [1, 3, -9, 2, 4]
输出:11
解释:排列后甜点为 [1, 3, -9, 2, 4, 1, 3, -9, 2, 4, 1, 3, -9, 2, 4]
选择 [2, 4, 1, 3, -9, 2, 4, 1, 3] 这段连续甜点,最大总喜爱值为 11

问题理解

我们需要在一个长度为 ( N \times M ) 的数组中找到一个连续子数组,使得其和最大。这个数组是由 ( M ) 次重复的 ( N ) 个甜点组成的。

数据结构选择

我们可以使用数组来存储甜点的喜爱值。

算法步骤

  1. 计算单次甜点的最大子数组和:使用Kadane算法来计算单次甜点的最大子数组和。

  2. 考虑重复甜点的影响

    • 如果最大子数组和是正数,那么我们可以考虑跨越多段甜点的情况。
    • 如果最大子数组和是负数,那么我们只需要考虑单次甜点的最大子数组和。

代码提示

以下是一些代码提示,帮助你实现这个算法: ef solution(N, M, data): # 使用Kadane算法计算单次甜点的最大子数组和 def kadane(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_segment = kadane(data)

# 如果M == 1,直接返回单次甜点的最大子数组和
if M == 1:
    return max_single_segment

# 计算整个数组的和
total_sum = sum(data)

# 计算前缀和和后缀和的最大值
max_prefix_sum = float('-inf')
current_prefix_sum = 0
for value in data:
    current_prefix_sum += value
    max_prefix_sum = max(max_prefix_sum, current_prefix_sum)

max_suffix_sum = float('-inf')
current_suffix_sum = 0
for value in reversed(data):
    current_suffix_sum += value
    max_suffix_sum = max(max_suffix_sum, current_suffix_sum)

# 考虑跨越多段甜点的情况
if total_sum > 0:
    max_sum = max(max_single_segment, 
                  max_prefix_sum + max_suffix_sum + (M - 2) * total_sum)
else:
    max_sum = max(max_single_segment, max_prefix_sum + max_suffix_sum)

return max_sum

if name == "main": # Add your test cases here print(solution(5, 1, [1, 3, -9, 2, 4]) == 6) print(solution(5, 3, [1, 3, -9, 2, 4]) == 11) ### 关键步骤解释

  1. Kadane算法:用于计算单次甜点的最大子数组和。
  2. 前缀和与后缀和:用于计算跨越多段甜点的情况。
  3. 总和的考虑:如果总和为正,考虑跨越多段甜点的情况;如果总和为负,则只考虑单次甜点的最大子数组和。 处理甜点喜爱值为负数的情况是这个问题的关键之一。我们需要确保在计算最大子数组和时,能够正确处理负数的影响。以下是一些关键点来帮助你处理这种情况:

关键点

  1. Kadane算法:Kadane算法本身就能够处理包含负数的情况。它会动态地更新当前子数组的最大和,即使中间有负数,只要后续的正数能够弥补,算法仍然能够找到最大和。
  2. 前缀和与后缀和:在计算前缀和与后缀和时,我们同样需要考虑负数的影响。我们需要确保在计算过程中,即使遇到负数,也能够正确更新最大前缀和和最大后缀和。
  3. 总和的考虑:如果总和为负数,我们需要特别注意跨越多段甜点的情况。如果总和为负数,跨越多段甜点可能不会带来额外的收益,因此我们只需要考虑单次甜点的最大子数组和。

题目收获总结

  1. 理解Kadane算法

    • 应用场景:Kadane算法是解决最大子数组和问题的经典算法。通过这个题目,你可以深入理解Kadane算法的工作原理和应用场景。
    • 动态更新:Kadane算法通过动态更新当前子数组的最大和,能够高效地找到最大子数组和,即使数组中包含负数。
  2. 处理重复数据

    • 数据重复的影响:题目中甜点被重复多次,这要求我们考虑跨越多段甜点的情况。通过这个题目,你可以学习如何处理重复数据,并计算跨越多段数据的最大和。
    • 前缀和与后缀和:通过计算前缀和与后缀和,我们可以有效地处理跨越多段数据的情况,确保在计算最大和时考虑所有可能的子数组。
  3. 边界条件处理

    • 单次甜点的情况:当 ( M = 1 ) 时,我们只需要计算单次甜点的最大子数组和。这帮助我们理解如何处理边界条件,确保算法在不同情况下都能正确运行。
    • 总和为负数的情况:如果总和为负数,跨越多段甜点可能不会带来额外的收益。通过这个题目,你可以学习如何根据总和的正负来调整算法,确保在不同情况下都能找到最大和。
  4. 代码优化与调试

    • 代码优化:通过这个题目,你可以学习如何优化代码,确保在处理大规模数据时能够高效运行。
    • 调试技巧:在实现算法时,可能会遇到各种问题。通过调试代码,你可以学习如何逐步排查问题,确保代码的正确性。

总结

通过这个题目,你不仅能够深入理解Kadane算法和最大子数组和问题,还能够学习如何处理重复数据、边界条件以及代码优化与调试。这些技能在实际编程中非常有用,能够帮助你更好地解决类似的问题。