【线性 dp】B012_LC_K 次串联后最大子数组之和(最大前后缀和 + 最大子数组 + 分类讨论)

一、Problem

给你一个整数数组 arr 和一个整数 k。首先,我们要对该数组进行修改,即把原数组 arr 重复 k 次。

举个例子,如果 arr = [1, 2] 且 k = 3,那么修改后的数组就是 [1, 2, 1, 2, 1, 2]。然后,请你返回修改后的数组中的最大的子数组之和。

注意,子数组长度可以是 0,在这种情况下它的总和也是 0。由于 结果可能会很大,所以需要 模(mod) 10^9 + 7 后再返回。

输入:arr = [1,-2,1], k = 5
输出:2

提示:

1 <= arr.length <= 10^5
1 <= k <= 10^5
-10^4 <= arr[i] <= 10^4

二、Solution

方法一:最大前后缀

最暴力的方法是遍历 n × k 次,遍历时通过对数组下标进行取模防止出界,实时记录子数组最大和,但会超时。这里分类讨论一下 k k 的情况:

  • k = 1 k = 1 ,直接求子数组最大和 mSum
  • k = 2 k = 2 ,答案可能由两个数组的最大后缀和 + 最大前缀和组成
  • k > 2 k > 2
    • 如果 t o t < 0 tot < 0 t o t tot 为数组总和),那么假如数组 a 为 [x1,x2,x3],那么拼接之后变为:
      [x1,x2,x3,x1,x2,x3,x1,x2,x3,x1,x2,x3],因为 sum < 0,所以 [x1,x2,x3,x1,x2,x3,x1,x2,x3,x1,x2,x3] 加粗的这一段总和也 < 0,所以当 k > 2 && sum < 0 时,考虑加入中间那一段和就不可能形成为答案了。
    • 如果 s u m 0 sum \geqslant 0 ,中间那一段显然可以被考虑进来,且它的总和可以很方便计算出来: ( k 2 ) × m S u m (k - 2) × mSum ,此时在类加上最大前后缀和即为答案。

最后要计算的量罗列一下:最大后缀和 mSuf、最大前缀和 mPre、最大子数组和 mSum

class Solution {
    public int kConcatenationMaxSum(int[] a, int k) {
        int n = a.length, mod = (int) 1e9+7, mSum = a[0], mPre = a[0], mSuf = a[n-1];
        int cur = 0, pre = 0, suf = 0;
        
        for (int i = 0; i < n; i++) {
            cur = cur > 0 ? (cur + a[i]) % mod : a[i];  //cur<=0的话,无论加上整数还是负数,都不会比直接用a[i]大
            mSum = Math.max(mSum, cur);    //最大子数组和

            pre = (pre + a[i]) % mod;
            suf = (suf + a[n-i-1]) % mod;
            mPre = Math.max(mPre, pre);    //最大前缀和
            mSuf = Math.max(mSuf, suf);    //最大后缀和
        }
        mPre = Math.max(0, mPre);
        mSuf = Math.max(0, mSuf);
        mSum = Math.max(0, mSum);
        int tot = pre, ans = 0;
        
        if (k == 1)
            ans = mSum;
        else if (k == 2)
            ans = Math.max(mSum, (mPre + mSuf) % mod);
        else {
            if (tot <= 0) {
                ans = Math.max(mSum, (mPre + mSuf) % mod);
            } else {
                long t = ((long) (k-2)*tot%mod + mPre + mSuf) % mod;	//这里的乘法可能会导致溢出
                ans = Math.max((int) t, mSum);
            }
        }
        return ans;
    }
}

复杂度分析

  • 时间复杂度: O ( n ) O(n)
  • 空间复杂度: O ( 1 ) O(1)

猜你喜欢

转载自blog.csdn.net/qq_43539599/article/details/106905513