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

56 阅读3分钟

一、题目理解

  • 核心目标:给定一个表示红包金额的数组 redpacks,通过做两次切割将其分成三部分,要使得第一部分和第三部分的红包总金额相等,最终求出第一部分所能达到的最大总金额。
  • 题目理解:即将数组 redpacks分成三部分,前后两部分要相等并且要最大的值,很容易理解到这个题目涉及前后双指针操作。

二、解题思路分析

  • 暴力解法思路

    • 通过两层循环来模拟两次切割的位置。外层循环控制第一次切割的位置,内层循环控制第二次切割的位置。
  • 双指针思路

    • 用两个指针 left 和 right,初始分别指向数组的开头和结尾。
    • 计算左边部分的和 left_sum 以及右边部分的和 right_sum,移动指针来调整两部分的和,使其尽量相等。
    • 如果 left_sum 小于 right_sum,就将 left 指针向右移动一位(意味着把下一个红包加到左边部分),同时更新 left_sum;反之,如果 left_sum 大于 right_sum,就将 right 指针向左移动一位,并更新 right_sum
    • 在移动指针的过程中,当 left_sum 和 right_sum 相等时,记录下此时左边部分的和,并与之前记录的最大相等金额比较,更新最大值。
    • 代码示例(Python 语言伪代码形式,体现思路)
    public static int solution(List<Integer> redpacks) {
        // Please write your code here
        int n = redpacks.size();
        if (n < 2)
            return 0; // 如果红包数量小于2,无法分成三部分

        int maxBonus = 0;
        int leftSum = redpacks.get(0);
        int rightSum = redpacks.get(n - 1);
        // 使用双指针遍历红包列表

        int left = 0;
        int right = n - 1;
        while (left < right) {
            if (leftSum == rightSum) {
                maxBonus = Math.max(leftSum, maxBonus);
                left++;
                right--;
                leftSum += redpacks.get(left);
                rightSum += redpacks.get(right);
            } else if (leftSum < rightSum) {
                left++;
                leftSum += redpacks.get(left);
            } else if (leftSum > rightSum) {
                right--;
                rightSum += redpacks.get(right);
            }
        }

        return maxBonus;
    }
  • 复杂度分析

    • 时间复杂度:指针最多遍历整个数组一次,时间复杂度为O(n),相比暴力解法有很大提升,n 为红包数组长度。
    • 空间复杂度:同样主要是几个指针和临时变量的使用,空间复杂度为O(1)。

三、代码解读

  • 通过 while 循环,只要左指针 left 小于右指针 right,就持续进行循环操作,不断调整指针位置以及对应的左右部分红包总金额,来寻找满足条件的情况。

  • 情况一:左右部分金额相等

    • 当 leftSum 等于 rightSum 时,说明找到了一种满足第一部分和第三部分红包总金额相等的情况。此时,通过 Math.max 函数将当前的 leftSum 和已记录的 maxBonus 进行比较,取较大值更新 maxBonus,因为我们要找的是最大的满足条件的金额。
    • 然后将 left 指针向右移动一位(left++),right 指针向左移动一位(right--),同时更新 leftSum 和 rightSum,把新指针指向的红包金额分别累加到对应的总和中,继续下一轮判断。
  • 情况二:左边部分金额小于右边部分金额

    • 当 leftSum < rightSum 时,意味着左边部分的红包总金额较小,需要将左指针向右移动,把下一个红包纳入左边部分,所以执行 left++,并且将新纳入的红包金额累加到 leftSum 中(leftSum += redpacks.get(left)),之后继续下一轮循环判断,期望通过这样的调整使左右两边金额逐渐接近相等。
  • 情况三:左边部分金额大于右边部分金额

    • 当 leftSum > rightSum 时,和情况二类似,不过此时是右边部分的红包总金额较小,需要将右指针向左移动,把新纳入的红包(也就是当前右指针新指向的红包)加到右边部分,执行 right-- 以及 rightSum += redpacks.get(right),然后继续下一轮循环判断。