这里简单讲解一下最大相等分割红包金额这道题,是一道比较简单的运用了前缀和思想的题目。
题目大意:
小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个元素的总和",求解从i到j之间的区间和的操作s[i]-s[j-1]可以理解为“从前i个元素的总和中去掉前j-1个元素的总和”。这里之所以使用j-1是因为s[j]包括了第j个元素,但是从i到j之间的区间和也包括了第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
```