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

56 阅读3分钟

这里简单讲解一下最大相等分割红包金额这道题,是一道比较简单的运用了前缀和思想的题目。

题目大意:

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

测试样例(这里直接给代码中的样例了):

样例1:

输入:[1, 3, 4, 6, 7, 14]

输出:14

样例解释:

按照下面的方法划分:“1,3,4,6”、“7”、“14”

样例2:

输入:[10000]

输出:0

样例解释:

无法将一排红包分成三部分,所以无法获得红包

样例3:

输入:[52, 13, 61, 64, 42, 26, 4, 27, 25]

输出:52

样例解释:

按照下面的方法划分:“52”、“13,61,64,42,26,4“、“27,25”。

只有这种划分方法才可以使第一部分与第三部分相等。

求解思路

第一眼看到这道题可以很简单的想到枚举每一个分割的点,但是难点在于如何求出每部分的金额总和。如果直接累加,那么每次枚举的时间复杂度就是O(n),这里就可以使用前缀和进行优化,将每次枚举的时间复杂度优化到O(1)

前缀和算法就是在枚举之前预处理出一个前缀和数组s[i],任何求区间和的操作都可以转化为前缀和数组中的元素相减,即s[i]-s[j-1],从而将时间复杂度优化到O(1)

其中,s[i]表示的含义为“从第一个元素开始到第i个元素的总和",求解从ij之间的区间和的操作s[i]-s[j-1]可以理解为“从前i个元素的总和中去掉前j-1个元素的总和”。这里之所以使用j-1是因为s[j]包括了第j个元素,但是从ij之间的区间和也包括了第j个元素,所以需要减去j前面的元素和,即s[j-1]

在预处理前缀和数组时需要注意的细节是数组下标往往从1开始,因为s[i]=s[i-1]+a[i](a[i]为原数组),下标从0开始会越界。

可以先去LeetCode做下这道题303. 区域和检索 - 数组不可变

下面是AC代码:

def solution(redpacks):
    n = len(redpacks)
    
    if n < 2:
        return 0
    
    # 计算前缀和数组
    prefix_sum = [0] * (n + 1)
    for i in range(1, n + 1):
        prefix_sum[i] = prefix_sum[i - 1] + redpacks[i - 1]
    
    max_amount = 0
    # print(prefix_sum)
    
    # 枚举第一部分的结尾位置 i
    for i in range(1, n+1):
        # 枚举第二部分的结尾位置 j
        for j in range(i + 1, n+1):
            # 检查第一部分和第三部分的总金额是否相等
            if prefix_sum[i] == prefix_sum[n] - prefix_sum[j-1]:
                max_amount = max(max_amount, prefix_sum[i])
    
    return max_amount
    ```