Files
leetcode-master/problems/kamacoder/0125.连续子数组最大和.md
programmercarl 96f4622dcf 图论更新
2024-06-13 10:29:09 +08:00

2.4 KiB
Raw Blame History

123.连续子数组最大和

这道题目可以说是 代码随想录,动态规划:最大子序和 的升级版。

题目求的是 可以替换一个数字 之后 的 连续子数组最大和。

如果替换的是数组下标 i 的元素。

那么可以用 代码随想录,动态规划:最大子序和 的方法,先求出 [0 - i) 区间的 最大子序和 dp1 和 (i, n)的最大子序和dp2 。

然后在遍历一遍i 计算 dp1 + dp2 + vec[i] 的最大值就可以。

正序遍历,求出 [0 - i) 区间的 最大子序dp[ i - 1] 表示 是 包括下标i - 1以vec[i - 1]为结尾的最大连续子序列和为dp[i - 1]。

所以 在计算区间 (i, n)即 dp2 的时候,我们要倒叙。 因为我们求的是以 包括下标i + 1 为起始位置的最大连续子序列和为dp[i + 1]。

这样 dp1 + dp2 + vec[i] 才是一个完整区间。

这里就体现出对 dp数组定义的把控本题如果对 dp数组含义理解不清其实是不容易做出来的。

代码:

#include <iostream>
#include <vector>
#include <climits>
using namespace std;
int main() {
    int t, n, x;
    cin >> t;
    while (t--) {
        cin >> n >> x;
        vector<int> vec(n);
        for (int i = 0; i < n; i++) cin >> vec[i];
        vector<int> dp1(n);
        dp1[0] = vec[0];
        int res = vec[0];
        // 从前向后统计最大子序和
        for (int i = 1; i < n; i++) {
            dp1[i] = max(dp1[i - 1] + vec[i], vec[i]); // 状态转移公式
            res = max(res, dp1[i]);
        }

        res = max(res, vec[n - 1]);
        // 从后向前统计最大子序和
        vector<int> dp2(n);
        dp2[n - 1] = vec[n - 1];
        for (int i = n - 2; i >= 0; i--) {
            dp2[i] = max(dp2[i + 1] + vec[i], vec[i]);

        }

        for (int i = 0 ; i < n ; i++) {
            int dp1res = 0;
            if (i > 0) dp1res = max(dp1[i-1], 0);
            int dp2res = 0;
            if (i < n - 1 ) dp2res = max(dp2[i+1], 0);

            res = max(res, dp1res + dp2res + x);
        }
        cout << res << endl;
    }

}