普通视图

发现新文章,点击刷新页面。
昨天以前首页

长度可被 K 整除的子数组的最大元素和

2025年11月20日 11:21

方法一:前缀和

思路与算法

令数组 $\textit{nums}$ 的前缀和为 $\textit{prefixSum}[i] = \sum^i_{j = 0}\textit{nums}[j]$,那么区间 $[j, i]$ 的子数组和为 $\textit{sum}(j, i) = \textit{prefixSum}[i] - \textit{prefixSum}[j - 1]$。题目要求非空子数组的长度可以被 $k$ 整除,即:

$$
(i - j + 1) \bmod k = 0
$$

那么有:

$$
i \bmod k = (j - 1) \bmod k
$$

使用 $\textit{kSum}[l]$ 记录下标同余为 $l$ 的所有前缀和最小值。根据上面的推导,对于每个 $i$,我们只需要找到一个与它同余的最小前缀和 $\textit{prefixSum}[j - 1]$,即 $\textit{kSum}[i \bmod k]$,就可以得到 $i$ 为末尾元素的子数组最大和 $\textit{prefixSum}[i] - \textit{kSum}[i \bmod k]$。返回最终的最大值即可。

代码

###C++

class Solution {
public:
    long long maxSubarraySum(vector<int>& nums, int k) {
        int n = nums.size();
        long long prefixSum = 0, maxSum = LONG_LONG_MIN;
        vector<long long> kSum(k, LONG_LONG_MAX / 2);
        kSum[k - 1] = 0;
        for (int i = 0; i < n; i++) {
            prefixSum += nums[i];
            maxSum = max(maxSum, prefixSum - kSum[i % k]);
            kSum[i % k] = min(kSum[i % k], prefixSum);
        }
        return maxSum;
    }
};

###Go

func maxSubarraySum(nums []int, k int) int64 {
    n := len(nums)
    prefixSum := int64(0)
    maxSum := int64(math.MinInt64)
    kSum := make([]int64, k)
    for i := 0; i < k; i++ {
        kSum[i] = math.MaxInt64 / 2
    }
    kSum[k - 1] = 0
    for i := 0; i < n; i++ {
        prefixSum += int64(nums[i])
        maxSum = max(maxSum, prefixSum - kSum[i % k])
        kSum[i % k] = min(kSum[i % k], prefixSum)
    }
    return maxSum
}

###Python

class Solution:
    def maxSubarraySum(self, nums: List[int], k: int) -> int:
        n = len(nums)
        prefixSum = 0
        maxSum = -sys.maxsize
        kSum = [sys.maxsize // 2] * k
        kSum[k - 1] = 0
        for i in range(n):
            prefixSum += nums[i]
            maxSum = max(maxSum, prefixSum - kSum[i % k])
            kSum[i % k] = min(kSum[i % k], prefixSum)
        return maxSum

###Java

class Solution {
    public long maxSubarraySum(int[] nums, int k) {
        int n = nums.length;
        long prefixSum = 0;
        long maxSum = Long.MIN_VALUE;
        long[] kSum = new long[k];
        for (int i = 0; i < k; i++) {
            kSum[i] = Long.MAX_VALUE / 2;
        }
        kSum[k - 1] = 0;
        for (int i = 0; i < n; i++) {
            prefixSum += nums[i];
            maxSum = Math.max(maxSum, prefixSum - kSum[i % k]);
            kSum[i % k] = Math.min(kSum[i % k], prefixSum);
        }
        return maxSum;
    }
}

###TypeScript

function maxSubarraySum(nums: number[], k: number): number {
    let n = nums.length;
    let prefixSum = 0;
    let maxSum = -Number.MAX_SAFE_INTEGER;
    let kSum: number[] = Array(k).fill(Number.MAX_SAFE_INTEGER / 2);
    kSum[k - 1] = 0;
    for (let i = 0; i < n; i++) {
        prefixSum += nums[i];
        maxSum = Math.max(maxSum, prefixSum - kSum[i % k]);
        kSum[i % k] = Math.min(kSum[i % k], prefixSum);
    }
    return maxSum;
}

###JavaScript

var maxSubarraySum = function(nums, k) {
    let n = nums.length;
    let prefixSum = 0;
    let maxSum = -Number.MAX_SAFE_INTEGER;
    let kSum = Array(k).fill(Number.MAX_SAFE_INTEGER / 2);
    kSum[k - 1] = 0;
    for (let i = 0; i < n; i++) {
        prefixSum += nums[i];
        maxSum = Math.max(maxSum, prefixSum - kSum[i % k]);
        kSum[i % k] = Math.min(kSum[i % k], prefixSum);
    }
    return maxSum;
};

###C#

public class Solution {
    public long MaxSubarraySum(int[] nums, int k) {
        int n = nums.Length;
        long prefixSum = 0;
        long maxSum = long.MinValue;
        long[] kSum = new long[k];
        for (int i = 0; i < k; i++) {
            kSum[i] = long.MaxValue / 2;
        }
        kSum[k - 1] = 0;
        for (int i = 0; i < n; i++) {
            prefixSum += nums[i];
            maxSum = Math.Max(maxSum, prefixSum - kSum[i % k]);
            kSum[i % k] = Math.Min(kSum[i % k], prefixSum);
        }
        return maxSum;
    }
}

###C

long long maxSubarraySum(int* nums, int numsSize, int k) {
    long long prefixSum = 0;
    long long maxSum = LONG_MIN;
    long long* kSum = (long long*)malloc(sizeof(long long) * k);
    for (int i = 0; i < k; i++) {
        kSum[i] = LLONG_MAX / 2;
    }
    kSum[k - 1] = 0;
    for (int i = 0; i < numsSize; i++) {
        prefixSum += nums[i];
        if (prefixSum - kSum[i % k] > maxSum) {
            maxSum = prefixSum - kSum[i % k];
        }
        if (prefixSum < kSum[i % k]) {
            kSum[i % k] = prefixSum;
        }
    }
    free(kSum);
    return maxSum;
}

###Rust

impl Solution {
    pub fn max_subarray_sum(nums: Vec<i32>, k: i32) -> i64 {
        let n = nums.len();
        let mut prefix_sum: i64 = 0;
        let mut max_sum: i64 = i64::MIN;
        let k = k as usize;
        let mut k_sum: Vec<i64> = vec![i64::MAX / 2; k];
        k_sum[k - 1] = 0;
        for i in 0..n {
            prefix_sum += nums[i] as i64;
            let idx = i % k;
            max_sum = max_sum.max(prefix_sum - k_sum[idx]);
            k_sum[idx] = k_sum[idx].min(prefix_sum);
        }
        max_sum
    }
}

复杂度分析

  • 时间复杂度:$O(n)$,其中 $n$ 为数组 $\textit{nums}$ 的长度。

  • 空间复杂度:$O(k)$。

❌
❌