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

67 阅读3分钟

简单记录一下《最大相等分割红包金额》这道题解题思路。

题面如下:

问题描述

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

样例1: 输入redpacks = [1,3,4,6,7,14],只有一种分割方式,即在67之间做第一次切分,在714之间做第二次切分,分成[1,3,4,6][7][14],同时保证第一部分和第三部分的总金额相等,最终该样例输出的最大金额为14。

样例2: 输入redpacks = [10000],无法分割成三个部分,最终该样例输出的最大金额为0。

样例3: 输入redpacks = [10,10,10,10],有两种分割方式,分成[10][10,10][10],或者分成[10,10][][10,10]。这两种分割方法同时保证第一部分和第三部分的总金额相等,选择金额最大的一种分法,故最终该样例输出的最大金额为20。

样例4: 输入redpacks = [7,7,7,21,7,7],有两种分割方式,分成[7][7,7,21,7][7],或者分成[7,7][7,21][7,7]。这两种分割方法同时保证第一部分和第三部分的总金额相等,选择金额最大的一种分法,故最终该样例输出的最大金额为14。

解题思路

题目要求我们对一组给定的数据做两次划分,使得左边的部分和右边的部分数字之和相等,同时左边/右边部分的数字之和要尽可能大。我们注意到数据无需重新进行排序,中间部分可以为空集。

下面我们先来独立思考一下这道题要怎么做:

1、由于我们需要计算左右两边的数字之和,这个问题很容易联想到使用前缀和来记录当前数字之和。因为左右两边互不相干,所以我们可以分开使用前缀和还有后缀和。我们可以定义前缀和数组 prefix_sum,记录从数组开头到当前位置的元素和;再定义后缀和数组 suffix_sum,记录从当前位置到数组末尾的元素和。

2、对于上面的两个数组的处理,我们可以采取双指针遍历所有的分割方法。具体来说,就是通过两个嵌套的for循环遍历所有可能得分割点,用外层循环i表示第一次分割的位置,内存循环j表示第二次分割的位置,同时确保内层的j要大于外层的i

3、对于每一对(i,j),计算第一部分和第三部分的和,并更新最大和,最终输出最大和。

具体的代码如下:

def solution(redpacks):
    n = len(redpacks)
    # 存储最大和
    max_sum = 0
    # 计算前缀和与后缀和
    prefix_sum = [0] * n
    suffix_sum = [0] * n
    prefix_sum[0] = redpacks[0]
    for i in range(1, n):
        prefix_sum[i] = prefix_sum[i - 1] + redpacks[i]
    suffix_sum[n - 1] = redpacks[n - 1]
    for i in range(n - 2, -1, -1):
        suffix_sum[i] = suffix_sum[i + 1] + redpacks[i]
    # 使用双指针遍历所有切法
    for i in range(n):
        for j in range(i + 1, n):
            # 计算第一组和第三组的和
            first_group_sum = prefix_sum[i]
            third_group_sum = suffix_sum[j]
            # 更新最大和
            if first_group_sum == third_group_sum and first_group_sum > max_sum:
                max_sum = first_group_sum
    return max_sum

运行代码,可以看见结果是正确的:

image.png