问题描述
小明在玩一个有趣的数字游戏,他有一个整数数组,代表每个数字的"能量值"。游戏允许他选择数组中的任意一个连续子数组,并将这个子数组内的所有数字翻转(正变负,负变正)一次。翻转操作只能执行一次。
翻转后,小明希望整个数组的最大子数组和尽可能大。注意,最大子数组和是指所有连续子数组中元素和最大的那个值。
请你帮助小明设计一个算法,找出在执行最多一次翻转操作后,整个数组可能的最大子数组和。
测试样例
样例1:
输入:
nums = [1, -2, 3, -4, 5]输出:9解释:翻转连续子数组 -2, 3, -4 后,数组变为 1, 2, -3, 4, 5。此时,最大子数组和是 4+5=9(子数组 4,5)。其他翻转方式得到的最大子数组和均小于9。
样例2:
输入:
nums = [-1, -2, -3]输出:6解释:翻转整个数组 -1, -2, -3 后,数组变为 1, 2, 3。此时,最大子数组和是 1+2+3=6(整个数组)。如果不翻转,最大子数组和为 -1(子数组 -1 或单个元素)。
样例3:
输入:
nums = [1, 2, 3]输出:6解释:数组本身已经全为正数,最大子数组和为 1+2+3=6。翻转任意子数组只会引入负数,降低最大子数组和,因此无需翻转。
约束条件
- 数组长度 n 满足:1 <= n <= 10^5
- 数组元素为整数,绝对值不超过 10^4
解题思路
要解决这个问题,关键在于理解翻转操作对最大子数组和的影响。翻转一个连续子数组(即将其每个元素符号取反)相当于改变了该段子数组的符号,这可能会创造新的最大子数组和。
常见的方法是使用动态规划来跟踪翻转和不翻转状态下的最大子数组和。具体来说,可以维护三个状态:
dp0:当前未进行任何翻转的最大子数组和dp1:当前已经进行过一次翻转的最大子数组和dp2:当前已经结束翻转(即翻转操作已结束)的最大子数组和
通过遍历数组,更新这些状态,最终max(dp0, dp1, dp2)即为所求答案。
这种方法的时间复杂度为 O(n),空间复杂度为 O(1),适用于大规模数据。
参考代码
python
def maxSumAfterFlip(nums):
dp0 = nums[0]
dp1 = -nums[0]
dp2 = nums[0]
res = max(dp0, dp1, dp2)
for i in range(1, len(nums)):
num = nums[i]
new_dp0 = max(num, dp0 + num)
new_dp1 = max(-num, dp0 - num, dp1 - num)
new_dp2 = max(num, dp1 + num, dp2 + num)
dp0, dp1, dp2 = new_dp0, new_dp1, new_dp2
res = max(res, dp0, dp1, dp2)
return res
cpp
public int maxSumAfterFlip(int[] nums) {
int dp0 = nums[0];
int dp1 = -nums[0];
int dp2 = nums[0];
int res = Math.max(Math.max(dp0, dp1), dp2);
for (int i = 1; i < nums.length; i++) {
int num = nums[i];
int new_dp0 = Math.max(num, dp0 + num);
int new_dp1 = Math.max(Math.max(-num, dp0 - num), dp1 - num);
int new_dp2 = Math.max(Math.max(num, dp1 + num), dp2 + num);
dp0 = new_dp0;
dp1 = new_dp1;
dp2 = new_dp2;
res = Math.max(res, Math.max(Math.max(dp0, dp1), dp2));
}
return res;
}
cpp
function maxSumAfterFlip(nums) {
let dp0 = nums[0];
let dp1 = -nums[0];
let dp2 = nums[0];
let res = Math.max(dp0, dp1, dp2);
for (let i = 1; i < nums.length; i++) {
const num = nums[i];
const new_dp0 = Math.max(num, dp0 + num);
const new_dp1 = Math.max(-num, dp0 - num, dp1 - num);
const new_dp2 = Math.max(num, dp1 + num, dp2 + num);
dp0 = new_dp0;
dp1 = new_dp1;
dp2 = new_dp2;
res = Math.max(res, dp0, dp1, dp2);
}
return res;
}
cpp
#include <vector>
#include <algorithm>
using namespace std;
int maxSumAfterFlip(vector<int>& nums) {
int dp0 = nums[0];
int dp1 = -nums[0];
int dp2 = nums[0];
int res = max({dp0, dp1, dp2});
for (int i = 1; i < nums.size(); i++) {
int num = nums[i];
int new_dp0 = max(num, dp0 + num);
int new_dp1 = max({-num, dp0 - num, dp1 - num});
int new_dp2 = max({num, dp1 + num, dp2 + num});
dp0 = new_dp0;
dp1 = new_dp1;
dp2 = new_dp2;
res = max({res, dp0, dp1, dp2});
}
return res;
}
cpp
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#define max(a, b) ((a) > (b) ? (a) : (b))
#define max3(a, b, c) max(max(a, b), c)
int maxSumAfterFlip(int* nums, int numsSize) {
int dp0 = nums[0];
int dp1 = -nums[0];
int dp2 = nums[0];
int res = max3(dp0, dp1, dp2);
for (int i = 1; i < numsSize; i++) {
int num = nums[i];
int new_dp0 = max(num, dp0 + num);
int new_dp1 = max3(-num, dp0 - num, dp1 - num);
int new_dp2 = max3(num, dp1 + num, dp2 + num);
dp0 = new_dp0;
dp1 = new_dp1;
dp2 = new_dp2;
res = max3(res, max3(dp0, dp1, dp2));
}
return res;
}
python
func maxSumAfterFlip(nums []int) int {
dp0 := nums[0]
dp1 := -nums[0]
dp2 := nums[0]
res := max(max(dp0, dp1), dp2)
for i := 1; i < len(nums); i++ {
num := nums[i]
new_dp0 := max(num, dp0 + num)
new_dp1 := max(-num, max(dp0 - num, dp1 - num))
new_dp2 := max(num, max(dp1 + num, dp2 + num))
dp0, dp1, dp2 = new_dp0, new_dp1, new_dp2
res = max(res, max(max(dp0, dp1), dp2))
}
return res
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
cpp
impl Solution {
pub fn max_sum_after_flip(nums: Vec<i32>) -> i32 {
let mut dp0 = nums[0];
let mut dp1 = -nums[0];
let mut dp2 = nums[0];
let mut res = dp0.max(dp1).max(dp2);
for i in 1..nums.len() {
let num = nums[i];
let new_dp0 = num.max(dp0 + num);
let new_dp1 = (-num).max(dp0 - num).max(dp1 - num);
let new_dp2 = num.max(dp1 + num).max(dp2 + num);
dp0 = new_dp0;
dp1 = new_dp1;
dp2 = new_dp2;
res = res.max(dp0).max(dp1).max(dp2);
}
res
}
}
程序代码
#include <stdio.h>
#define max(a, b) ((a) > (b) ? (a) : (b))
#define max3(a, b, c) max(max(a, b), c)
int maxSumAfterFlip(int* nums, int numsSize) {
if (numsSize == 1) return nums0;
int NEG = -1000000000;
int dp0 = nums0; // 未翻转
int dp1 = -nums0; // 翻转中,长度=1
int dp2 = NEG; // 翻转中,长度≥2
int dp3 = NEG; // 翻转已结束
int res = max(dp0, dp1);
for (int i = 1; i < numsSize; i++) {
int num = numsi;
int new_dp0 = max(num, dp0 + num);
int new_dp1 = max(-num, dp0 - num);
int new_dp2 = max(dp1 - num, dp2 - num);
int new_dp3 = max3(num, dp2 + num, dp3 + num);
dp0 = new_dp0;
dp1 = new_dp1;
dp2 = new_dp2;
dp3 = new_dp3;
res = max(res, max(max(dp0, dp1), max(dp2, dp3)));
}
return res;
}
int main() {
int nums1\[\] = {1, -2, 3, -4, 5};
int nums2\[\] = {-1, -2, -3};
int nums3\[\] = {1, 2, 3};
printf("%d\n", maxSumAfterFlip(nums1, 5)); // 9
printf("%d\n", maxSumAfterFlip(nums2, 3)); // 6
printf("%d\n", maxSumAfterFlip(nums3, 3)); // 6
return 0;
}
cpp
#include <stdio.h>
#define max(a, b) ((a) > (b) ? (a) : (b))
#define max3(a, b, c) max(max(a, b), c)
int maxSumAfterFlip(int* nums, int numsSize) {
if (numsSize == 1) return nums[0];
int NEG = -1000000000;
int dp0 = nums[0]; // 未翻转
int dp1 = -nums[0]; // 翻转中,长度=1
int dp2 = NEG; // 翻转中,长度≥2
int dp3 = NEG; // 翻转已结束
int res = max(dp0, dp1);
for (int i = 1; i < numsSize; i++) {
int num = nums[i];
int new_dp0 = max(num, dp0 + num);
int new_dp1 = max(-num, dp0 - num);
int new_dp2 = max(dp1 - num, dp2 - num);
int new_dp3 = max3(num, dp2 + num, dp3 + num);
dp0 = new_dp0;
dp1 = new_dp1;
dp2 = new_dp2;
dp3 = new_dp3;
res = max(res, max(max(dp0, dp1), max(dp2, dp3)));
}
return res;
}
int main() {
int nums1[] = {1, -2, 3, -4, 5};
int nums2[] = {-1, -2, -3};
int nums3[] = {1, 2, 3};
printf("%d\n", maxSumAfterFlip(nums1, 5)); // 9
printf("%d\n", maxSumAfterFlip(nums2, 3)); // 6
printf("%d\n", maxSumAfterFlip(nums3, 3)); // 6
return 0;
}
运行结果
