leetcode
leetcode 1151 ~ 1200
拼接数组的最大分数

拼接数组的最大分数

难度:

标签:

题目描述

代码结果

运行时间: 71 ms, 内存: 30.8 MB


/*
 * Problem: Given two integer arrays nums1 and nums2, both of length n, you can choose two integers left and right such that 0 <= left <= right < n and swap the subarrays nums1[left...right] and nums2[left...right].
 * You can perform this operation once or not at all. The score of the arrays is the maximum value of sum(nums1) and sum(nums2).
 * Return the maximum possible score.
 */

import java.util.stream.IntStream;

public class MaxScoreAfterSwapStream {
    public static int maxScoreAfterSwap(int[] nums1, int[] nums2) {
        int sum1 = IntStream.of(nums1).sum();
        int sum2 = IntStream.of(nums2).sum();

        int maxScore = Math.max(sum1, sum2);
        int diff1 = 0, diff2 = 0;

        for (int i = 0; i < nums1.length; i++) {
            diff1 += nums2[i] - nums1[i];
            diff2 += nums1[i] - nums2[i];
            maxScore = Math.max(maxScore, Math.max(sum1 + diff1, sum2 + diff2));
            if (diff1 < 0) diff1 = 0;
            if (diff2 < 0) diff2 = 0;
        }

        return maxScore;
    }

    public static void main(String[] args) {
        int[] nums1 = {20, 40, 20, 70, 30};
        int[] nums2 = {50, 20, 50, 40, 20};
        System.out.println(maxScoreAfterSwap(nums1, nums2)); // Output: 220
    }
}

解释

方法:

本题解使用了贪心算法与Kadane算法(最大子数组和)的思想。首先,可以观察到交换子数组后,nums1与nums2的总和不变,变化的只是两者的分配。因此,问题转化为找到一段区间(子数组),使得在交换后,两个数组中的最大总和最大。对于任何一对位置i,交换nums1[i]与nums2[i]得到的增益是(nums2[i] - nums1[i])。我们要找的是一个子数组,使得这个增益最大化。这可以通过Kadane算法实现,即计算最大子数组和,然后将这个最大增益加到原始数组nums1的总和上。为了确保考虑了所有可能,还需要从nums2的角度做同样的计算,即将nums1与nums2的角色互换,再次计算最大增益并加到nums2的总和上。最后,比较这两种情况的结果,取最大值。

时间复杂度:

O(n)

空间复杂度:

O(1)

代码细节讲解

🦆
为什么在计算增益时,使用的是(nums2[i] - nums1[i]),这里的逻辑是什么?
在计算增益时使用(nums2[i] - nums1[i])是为了确定交换nums1[i]和nums2[i]后的分数变化量。增益的计算反映了交换这两个元素后nums1数组的总和增加了多少。如果nums2[i]大于nums1[i],那么交换后nums1的总和会增加(nums2[i] - nums1[i]),这是因为我们把一个较大的数nums2[i]加到了nums1中,同时移除了一个较小的数nums1[i]。因此,这种计算方式可以直接评估每一次交换带来的净收益,帮助我们决定是否进行此交换以达到最大化nums1的总和。
🦆
Kadane算法通常用于寻找最大子数组和,如何确保这里应用Kadane算法来计算增益是合适的?
Kadane算法适用于本问题是因为我们需要找到一个子数组(即连续元素的集合),使得其对总和的正向贡献最大化。在本题中,每个元素的增益是(nums2[i] - nums1[i]),我们要找的是这些增益值组成的子数组,它们的总和最大。Kadane算法恰好用于快速找出一个数组中的最大子数组和,这使得它成为计算由增益构成的数组的最大子数组和的理想选择。通过这种方式,我们可以有效地找到最优的交换策略,即在哪个连续子区间进行交换可以最大化改进数组的总和。
🦆
在解法中提到的`如果当前子数组和小于0,重置为0`,这样做的目的是什么?
在Kadane算法中,如果当前子数组和小于0,将其重置为0是因为负的子数组和对寻找最大子数组总和没有帮助,反而会减少总和。当我们遇到这种情况时,意味着从当前位置开始重新计算子数组和可能得到一个更大的值。这是因为任何包含负总和的前缀都不能是最优的子数组的一部分,所以重置子数组和可以帮助我们摆脱之前的负积累,从当前点重新开始计算,可能找到一个新的、更大的子数组和。
🦆
题解中提到要从nums1和nums2两个角度分别计算,这种方法是否总是能保证找到全局最优解?
从nums1和nums2两个角度分别计算可以保证找到全局最优解,因为这种方法考虑了所有可能的交换方案。通过分别以nums1和nums2作为基准数组并计算最大增益,我们可以确保不遗漏任何一个可能导致总和增加的交换方案。然后通过比较这两种情况的结果,我们可以选择两者中的最大值,这确保了无论最佳交换策略属于哪一个数组,都能被正确考虑并实现最大化总和的目标。

相关问题