leetcode
leetcode 801 ~ 850
环形子数组的最大和

环形子数组的最大和

难度:

标签:

题目描述

代码结果

运行时间: 61 ms, 内存: 20.0 MB


/*
 * 思路:
 * 1. 使用Stream计算总和、标准最大子数组和和最小子数组和。
 * 2. 使用Stream的reduce方法来简化计算。
 * 3. 特殊情况处理:如果最大子数组和小于0,返回最大子数组和。
 */
import java.util.Arrays;

public class Solution {
    public int maxSubarraySumCircular(int[] nums) {
        int totalSum = Arrays.stream(nums).sum();
        int maxSum = Arrays.stream(nums).reduce(Integer.MIN_VALUE, (max, num) -> Math.max(max + num, num));
        int currentMax = 0;
        for (int num : nums) {
            currentMax = Math.max(currentMax + num, num);
            maxSum = Math.max(maxSum, currentMax);
        }
        int minSum = Arrays.stream(nums).reduce(Integer.MAX_VALUE, (min, num) -> Math.min(min + num, num));
        int currentMin = 0;
        for (int num : nums) {
            currentMin = Math.min(currentMin + num, num);
            minSum = Math.min(minSum, currentMin);
        }
        if (maxSum < 0) {
            return maxSum;
        }
        return Math.max(maxSum, totalSum - minSum);
    }
}

解释

方法:

此题解通过考虑两种情况来寻找最大子数组和:1. 子数组不包含环形的部分,即子数组完全位于数组的一个连续部分内。2. 子数组包含环形的部分,即子数组的一部分在数组的开头,另一部分在数组的结尾。对于第一种情况,直接使用Kadane算法找到最大子数组和。对于第二种情况,计算整个数组的总和,然后使用Kadane算法寻找非循环部分的最小子数组和,从总和中减去这个最小值,得到环形的最大子数组和。最后,比较这两种情况下的最大值,返回较大者。

时间复杂度:

O(n)

空间复杂度:

O(1)

代码细节讲解

🦆
为什么在计算环形子数组的最大和时,需要从总和中减去非环形部分的最小子数组和?
在环形数组中,若选择包含环状连接的子数组,实际上是选择了数组两端的元素同时排除了数组中间某段元素。所以,计算这种情况下的最大子数组和可以转换为求整个数组的总和减去中间某段的最小子数组和。这样,剩余部分即为所求的包含环状连接的最大子数组和。
🦆
在此题解中,若数组全部元素为负数,使用Kadane算法寻找最小子数组和是否会影响最终结果?
如果数组全部元素为负数,使用Kadane算法找到的最小子数组和可能等于整个数组的总和。此时从总和中减去这个最小子数组和结果为0。然而,最优解应为单个最小负数值,而非0。因此,在全负数情况下,直接使用Kadane算法找到的非环形最大子数组和(即最大单个元素)为最终结果,无需进行环形考虑。
🦆
在计算非环形部分的最小子数组和时,为什么选择跳过数组的首尾元素?
跳过数组的首尾元素是为了避免整个数组被视为一个非环形的部分,这是因为我们的目的是找出一个真正的中间部分来减去。如果包括首尾元素,则可能出现计算得到的最小子数组和为整个数组的情况,这将违背寻找环形子数组的初衷(至少需要包含数组的一部分环形连接)。
🦆
在题解中,如何确保减去的非环形部分最小子数组和不是整个数组的总和,即确保子数组不为空?
在题解中,通过特意不包括数组的第一个和最后一个元素来找最小子数组和的方式,避免了选取整个数组作为最小子数组的可能。这样确保了所减去的部分不会是整个数组的总和,从而保证了非空的子数组。这是为了正确地计算包含环形连接的子数组的最大和。

相关问题