AI 刷题 最大相等分割红包金额题解 | 豆包MarsCode AI刷题

109 阅读4分钟

最大相等分割红包金额题解

问题描述

小U在公司年会上赢得了一等奖,作为奖励,他有机会在一排红包中做两次切割,将红包分成三部分。要求第一部分和第三部分的红包总金额相等。他可以获得的金额是第一部分红包的总金额。现在的问题是,给定红包的金额列表,计算出小U能从这些红包中拿到的最大奖金金额。

思路解析

这个问题可以通过前缀和(prefix sum)来有效求解。我们需要进行两次切割,且要求切割后第一部分和第三部分的金额相等。通过前缀和可以快速计算任意区间的和,从而简化问题的求解过程。

具体思路:

  1. 前缀和:首先我们可以计算出一个前缀和数组prefix_sum,其中prefix_sum[i]表示从第一个红包到第i个红包的总和。这样,通过prefix_sum数组可以快速得到任何子数组的和。

  2. 找切割点:我们需要在红包列表中选择两个切割点,分别将红包分成三部分。我们假设切割点j是第二部分的结束位置。

  3. 条件判断:为了满足题目要求,第一部分和第三部分的总金额必须相等,如果满足条件,我们可以更新最大奖金金额。

解题代码

def solution(redpacks):
    n = len(redpacks)
    if n < 3:
        return 0

    prefix_sum = [0] * (n + 1)
    for i in range(n):
        prefix_sum[i + 1] = prefix_sum[i] + redpacks[i]

    max_amount = 0

    # 遍历
    for j in range(2, n):
        seen_sums = set()

        for i in range(1, j + 1):
            if prefix_sum[i] == prefix_sum[n] - prefix_sum[j]:
                seen_sums.add(prefix_sum[i])
                max_amount = max(max_amount, prefix_sum[i])

    return max_amount

if __name__ == "__main__":
    # Add your test cases here
    print(solution([1, 3, 4, 6, 7, 14]) == 14)
    print(solution([10000]) == 0)
    print(solution([52, 13, 61, 64, 42, 26, 4, 27, 25]) == 52)

解题思路详解

  1. 前缀和的计算: 首先,我们创建一个prefix_sum数组,其中prefix_sum[i]表示从第一个红包到第i个红包的总和。计算方法是,prefix_sum[i]等于prefix_sum[i-1]加上当前红包的金额。

  2. 遍历切割位置

    • 我们从第二个位置开始考虑切割点j,因为切割的第二部分必须包含至少一个红包。
    • 对于每一个切割点j,我们遍历从1到j-1的所有可能的切割位置i,检查是否满足条件:prefix_sum[i] == prefix_sum[n] - prefix_sum[j]。如果满足条件,则表示第一部分和第三部分的总金额相等。
  3. 更新最大奖金: 当满足条件时,我们将prefix_sum[i]更新为当前的最大奖金金额,并继续寻找其他可能的组合。

  4. 返回结果: 最终返回最大奖金金额,如果没有找到合法的组合,则返回0。

复杂度分析

  • 时间复杂度

    计算前缀和需要O(n)时间。对于每个j,我们遍历所有i(i小于j),最坏情况下是O(n^2)。因此,总的时间复杂度为O(n^2),其中n是红包的数量。

  • 空间复杂度

    我们使用了一个长度为n+1的数组prefix_sum来存储前缀和,空间复杂度是O(n)。 另外,seen_sums是一个集合,用来记录每次遇到的前缀和,空间复杂度也是O(n)。 因此,空间复杂度是O(n)

感受与注意事项

  1. 边界情况: 如果红包的数量小于3个,就无法进行有效的切割,因为无法将红包分成三部分。在这种情况下,我们直接返回0。

  2. 前缀和的高效性: 使用前缀和数组使得我们能够在常数时间内计算任意子数组的和,从而有效地简化了问题的复杂度。没有使用前缀和的情况下,我们需要重复计算多个子数组的和,这会导致效率低下。

  3. 理解切割点的选择: 切割点i和j的选择是关键。切割点i应该在1到j-1之间,确保第一部分和第三部分都包含至少一个红包。切割点j应该从2开始,确保第三部分不为空。