(动态规划)
这道题目是 NC19 连续子数组的最大和 的升级版,增加了环形情况。
分两种情况考虑问题:
-
无环情况下:求出连续子数组的最大值 res
-
有环情况下:先求出无环情况下连续子数组的最小值 res2,然后用数组和 sum 减去最小值 res2 即为环形情况下的连续子数组最大值。
why? 因为数组的和是固定的,从中间挑一段和最小,那么剩下尾首相连的一段和就是最大的。这个说法应该是最容易理解的。
特殊情况:当 res < 0 时,观察状态转移公式:f[i] = max(f[i - 1], 0) + nums[i]
,如果数组中有一个非负数,最大值也不会小于 0,那么说明全是负数,此时的最大值就是负数中最大的那个,直接返回即可。
时间复杂度
空间复杂度
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param nums int整型vector
* @return int整型
*/
int maxSubarraySumCircular(vector<int>& nums) {
int n = nums.size();
int sum = 0;
for (auto x : nums) sum += x;
// 求无环情况下连续子数组的最大值
int res = INT_MIN;
for (int i = 0, last = 0; i < n; i ++ ) {
last = max(last, 0) + nums[i];
res = max(res, last);
}
// 求无环情况下连续子数组的最小值
int res2 = INT_MAX;
for (int i = 0, last = 0; i < n; i ++ ) {
last = min(last, 0) + nums[i];
res2 = min(res2, last);
}
// 如果无环情况下 res < 0 说明全是负数,那么此时的最大值就是负数中最大的那个,直接返回即可。
// 有环情况下就没必要判断了。
if (res < 0) return res;
// sum - res2 表示环形情况下的连续子数组最大值,因为 res2 最小,sum - res2 就最大
return max(res, sum - res2);
}
};