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

46 阅读2分钟

问题描述

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

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

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

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

思路解释

本题我们需要在重复排列的甜点序列中找到一段连续甜点的最大喜爱值。其关键点在于理解甜点的重复排列和如何处理跨越多段的情况。

具体算法思路如下:

  • Kadane 算法:用于计算单段的最大子数组和。
  • 总和的正负情况:如果总和为正,多段的最大子数组和可以通过 max_two_segments + (M - 2) * total_sum 计算;如果总和为负,多段的最大子数组和可以通过 max_two_segments 计算。
  • 前缀和优化:考虑使用前缀和数组来加速计算跨越多段的最大子数组和。

详细代码

def solution(N, M, data):
    # 计算单段的最大子数组和
    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_two_segments = kadane(data + data)

    # 计算多段的最大子数组和
    # 这里需要考虑跨越多段的情况
    # 提示:考虑 total_sum 的正负情况
    if total_sum > 0:
        # 如果总和为正,多段的最大子数组和可以通过以下方式计算
        max_multi_segments = max_two_segments + (M - 2) * total_sum
    else:
        # 如果总和为负,多段的最大子数组和可以通过以下方式计算
        max_multi_segments = max_two_segments

    # 返回最大值
    return max(max_single_segment, max_multi_segments)

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 算法

    • kadane(arr) 函数用于计算单段的最大子数组和。
    • max_single_segment = kadane(data) 计算单段的最大子数组和。
  2. 两段的最大子数组和max_two_segments = kadane(data + data) 计算两段的最大子数组和。

  3. 多段的最大子数组和

    • 如果 total_sum > 0,计算 max_two_segments + (M - 2) * total_sum
    • 如果 total_sum <= 0,直接使用 max_two_segments