leetcode
leetcode 1101 ~ 1150
K 次串联后最大子数组之和

K 次串联后最大子数组之和

难度:

标签:

题目描述

代码结果

运行时间: 58 ms, 内存: 27.6 MB


/* 
题目思路:
1. 使用Java Stream对数组进行处理。
2. 需要对流的元素进行聚合计算。
3. 使用Stream API来实现Kadane算法。
4. 需要考虑数组和前缀和、后缀和以及数组整体和的处理。
*/

import java.util.Arrays;

public class Solution {
    public int kConcatenationMaxSum(int[] arr, int k) {
        int MOD = 1000000007;
        long maxSubarraySum = kadane(arr);
        if (k == 1) {
            return (int)(maxSubarraySum % MOD);
        }
        long prefixSum = 0, suffixSum = 0, maxPrefixSum = 0, maxSuffixSum = 0;
        long totalSum = Arrays.stream(arr).asLongStream().sum();
        long currentSum = 0;
        for (int x : arr) {
            currentSum += x;
            prefixSum = Math.max(prefixSum, currentSum);
        }
        currentSum = 0;
        for (int i = arr.length - 1; i >= 0; i--) {
            currentSum += arr[i];
            suffixSum = Math.max(suffixSum, currentSum);
        }
        if (totalSum > 0) {
            return (int)((maxPrefixSum + maxSuffixSum + (totalSum * (k - 2))) % MOD);
        } else {
            return (int)(Math.max(maxPrefixSum + maxSuffixSum, maxSubarraySum) % MOD);
        }
    }
    private long kadane(int[] arr) {
        return Arrays.stream(arr)
            .mapToLong(x -> x)
            .collect(() -> new long[2], (a, b) -> {
                a[0] = Math.max(0, a[0] + b);
                a[1] = Math.max(a[1], a[0]);
            }, (a, b) -> {
                a[0] = Math.max(a[0], b[0]);
                a[1] = Math.max(a[1], b[1]);
            })[1];
    }
}

解释

方法:

该题解利用了Kadane算法来找出最大的子数组和,同时考虑了数组被重复k次时的不同情况: 1. 当数组总和为正时,最大和可能包括中间多个完整的数组和两头的部分数组。这种情况下,计算方式为两个数组的最大子数组和加上中间k-2个数组的总和。 2. 当数组总和不为正时,最大子数组和只可能出现在前两个数组内,因为更多的重复只会增加非正的总和。 3. 当k小于或等于2时,不需要考虑多个数组的累加总和,只需计算前k个数组内的最大子数组和。

时间复杂度:

O(n)

空间复杂度:

O(1)

代码细节讲解

🦆
在题解中提到,当数组总和为正时,最大和可能包括中间多个完整的数组和两头的部分数组,能否详细解释这种情况下的计算逻辑和原因?
当数组总和为正时,重复数组k次可以看作是提供了一个机会,使得通过选择多个完整的数组副本来增加总和成为可能。在这种情况下,最大子数组和可能由三部分组成:第一部分是从第一个数组中选择的最大子数组的结束部分;第二部分是中间的k-2个完整数组的总和;第三部分是从最后一个数组中选择的最大子数组的开始部分。这种组合可以实现当数组总和为正时的最大化收益,因为每增加一个完整的数组副本,总和都会增加。
🦆
题解使用了Kadane算法处理至多两倍数组长度,为什么选择遍历两倍数组长度是足够的?是否有可能丢失更长数组中的某些最大子数组和情况?
通过遍历两倍数组长度,我们可以覆盖所有单个数组和两个连续数组组合的可能的最大子数组和情况。这是因为最大子数组可能起始于第一个数组末尾并结束在第二个数组开始,或者仅存在于一个数组内部。遍历超过两倍长度不会发现新的最大子数组情况,因为任何更长的重复只会是前两个数组模式的重复,特别是当数组总和为负或零时,更多的重复并不会产生更大的子数组和。
🦆
题解中提到,当k小于或等于2时,只需要计算前k个数组内的最大子数组和,这里的逻辑是否意味着对于所有k > 2的情况,数组总和为负或零时最大子数组和一定为0?
题解中的逻辑确实表明,当k > 2且数组总和为负或零时,最大子数组和不会超过两个数组长度内找到的最大子数组和。这是因为,如果整个数组的总和不为正,那么重复数组只会增加更多的非正总和,从而不可能通过添加更多的数组副本来增加最大的子数组和。因此,对于k > 2的情况,如果数组总和为负或零,我们只需考虑最初两个数组内的最大子数组和,再多的重复也不会提高这个值。
🦆
题解中将最终结果模上109 + 7,这一步骤在算法中的作用是什么?为什么这样做是必要的?
在计算机科学中,特别是在处理大数和避免整数溢出的算法问题时,常常使用取模操作来保持数值在一个安全的可管理的范围内。将结果模上一个大质数(如10^9 + 7)可以防止结果因为数值过大而溢出,同时也是许多编程比赛和在线判题系统的常见要求,以保证结果的一致性和比较。

相关问题