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

65 阅读3分钟

题目链接

最大相等分割红包金额 - MarsCode

1.题意的转换

题目要求从一排红包中找到两次切割点,使得三部分的总金额满足:

  • 第一部分总金额 = 第三部分总金额。

我们可以把问题简化为寻找两个切割点(l 和 r),使得满足以下条件:

  1. 第一部分红包金额 = 从红包序列开头到切割点 l 的金额之和。
  2. 第三部分红包金额 = 从切割点 r 到红包序列末尾的金额之和。
  3. 上述两部分金额相等时,我们更新答案为当前的第一部分总金额,并继续寻找更大的可能值。

为有效实现这一目标,我们需要借助 前缀和 和 双指针 算法。

2. 算法思想讲解

1. 前缀和

前缀和是一种常见的算法技巧,用于快速计算数组中任意区间的元素之和。具体来说:

  • 设 sum[i] 表示数组前 i 个元素的累加和,即:sum[i]=redpacks[0]+redpacks[1]+⋯+redpacks[i−1]sum[i]=redpacks[0]+redpacks[1]+⋯+redpacks[i−1]
  • 有了前缀和,任何区间 [a, b] 的和都可以在 O(1) 时间内通过公式计算:区间和=sum[b]−sum[a]区间和=sum[b]−sum[a]

在本题中:

  • 我们通过前缀和快速计算从头到切割点 l 的金额(第一部分的金额)。
  • 同样,可以计算从切割点 r 到数组末尾的金额(第三部分的金额)。

2. 双指针

双指针是一种常用于数组问题的优化算法,旨在通过两个指针移动来缩小搜索空间。本题中,双指针应用如下:

  • 一个指针 l 用于标记第一部分的结束位置(切割点)。
  • 另一个指针 r 用于标记第三部分的起始位置(第二个切割点)。
  • 我们同时移动 l 和 r,以找到满足条件的切割点组合。

通过双指针,我们可以在 O(n) 的时间复杂度内找到最优解,而不需要暴力枚举所有可能的切割点组合。

3. 解题步骤

具体解题步骤

1. 计算前缀和

使用一个数组 sum 存储红包序列的前缀和:

  • 初始化 sum[0] = 0
  • 遍历数组,依次计算 sum[i] = sum[i-1] + redpacks[i-1]

2. 初始化双指针

  • l 从 1 开始,因为第一部分至少需要有一个红包。
  • r 从数组末尾开始,保证第三部分至少有一个红包。

3. 双指针遍历寻找最大值

  • 使用循环,当 l < r 时,计算当前的两部分金额:suml=sum[l],sumr=sum[n]−sum[r−1]suml=sum[l],sumr=sum[n]−sum[r−1]
  • 如果 suml == sumr,更新答案,并移动指针 l,尝试找到更大的可能值。
  • 如果 suml < sumr,说明第一部分金额较小,移动 l 向右扩展。
  • 如果 suml > sumr,说明第三部分金额较小,移动 r 向左收缩。

4. 返回结果

当循环结束时,结果 res 即为小U可以获得的最大奖金金额。

4 . 具体代码

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int solution(vector<int> redpacks) {
    int n = redpacks.size();
    int res = 0;
    vector<int> sum(n + 1, 0);

    // 前缀和计算
    for (int i = 1; i <= n; ++i) {
        sum[i] = sum[i - 1] + redpacks[i - 1];
    }

    int l = 1, r = n; // 双指针初始值

    while (l < r) { // 遍历所有可能的切割点
        int suml = sum[l]; // 左部分前缀和
        int sumr = sum[n] - sum[r - 1]; // 右部分和

        if (suml == sumr) {
            res = max(res, suml);
            l++; // 或移动一个指针
        } else if (suml < sumr) {
            l++;
        } else {
            r--;
        }
    }

    return res;
}

算法复杂度分析

  1. 时间复杂度

    • 前缀和计算:O(n)。
    • 双指针遍历:每个指针最多移动 nn 次,总计 O(n)O(n)。
    • 总体复杂度为 O(n)。
  2. 空间复杂度

    • 仅需一个长度为 n+1n+1 的前缀和数组 sum,空间复杂度为 O(n)。