通过将任何子数组的元素的符号反转最多两次来最大化子数组和
给定一个大小为n的数组A ,在应用给定操作最多两次后找到最大子数组和。在一次操作中,选择任意两个索引i和j并将索引i到索引j 的所有元素的符号反转,即 i 到 j 范围内的所有正元素变为负,所有负元素变为正。
例子:
Input: A[] = {1, -2, -4, 3, 5, -6}
Output: 21
Explanation:
Inverting the array from index 1 to index 2 & from index 5 to index 5 (0-based indexing) to get {1, 2, 4, 3, 5, 6} with maximum subarray sum = 21
Input: A[] = {2, -1, -18, 3, -1, -39, 5, -2}
Output: 69
方法:这个想法是首先,将所有元素合并到组中。即所有连续的正元素将被求和为一个整数,并将被放置在一个新的数组arr中,对于连续的负元素也是如此。之后,问题减少到在从该数组中反转最多两个元素后找到最大子数组和。
这个想法是使用动态编程。现在,创建一个dp[n][3]数组,并在该 dp 数组中的每个索引处,维护三个数字:
- 第一个数字表示将数组中的无元素取反后的最大子数组和。因此, dp[i][0]将简单地运行 kadane 算法的逻辑以获得最大子数组和。
- 第二个数字表示恰好反转数组中的一个元素后的最大子数组和。因此, dp[i][1]将是两个值的最大值,即dp[i-1][1] + arr[i] (将一个元素反转到 i 然后将当前元素添加到其中后的最大子数组总和)和dp[i][0]+ (-arr[i]) (即前一个非反转最大子数组总和直到 i-1,然后在反转后添加当前元素)。
- 第三个数字表示恰好反转数组中的两个元素后的最大子数组和。因此, dp[i][2]将是两个值的最大值,即 (将一个元素反转到 i-1 后的最大子数组总和,然后在反转后添加当前元素)和 (将两个元素反转直到 i-1 并将当前元素添加到其中后的最大子数组总和)。
- 保留一个maxSum变量,该变量将在每个索引后更新,并且等于maxSum的前一个值和所有三个当前值的最大值,即dp[i][0]、dp[i][1] 和 dp[i] [2]。
- 返回maxSum ,这就是答案。
下面是上述方法的实现:
C++
// C++ program for the above approach
#include
using namespace std;
// Function to merge alternate elements into groups
// of positive and negative
void mergeElements(int n, vector& arr, int* A)
{
int i = 0;
int sum = 0;
while (i < n) {
sum = 0;
while (i < n && A[i] >= 0) {
sum += A[i];
i++;
}
if (sum > 0) {
arr.push_back(sum);
}
sum = 0;
while (i < n && A[i] < 0) {
sum += A[i];
i++;
}
if (sum < 0) {
arr.push_back(sum);
}
}
}
// Function to return the maximum
// after inverting at most 2 elements
int findMaxSum(vector& arr, int n)
{
int maxSum = 0;
vector > dp(
n,
vector(3, INT_MIN));
dp[0][0] = max(0, arr[0]);
dp[0][1] = -1 * arr[0];
for (int i = 1; i < n; ++i) {
// dp[i][0] represents sum till ith index
// without inverting any element.
dp[i][0] = max(arr[i],
dp[i - 1][0] + arr[i]);
// dp[i][1] represents sum till ith index
// after inverting one element.
dp[i][1] = max(0, dp[i - 1][0]) - arr[i];
if (i >= 1) {
dp[i][1] = max(dp[i][1],
dp[i - 1][1] + arr[i]);
// dp[i][2] represents sum till ith index
// after inverting two elements.
dp[i][2] = dp[i - 1][1] - arr[i];
}
if (i >= 2) {
dp[i][2] = max(dp[i][2],
dp[i - 1][2] + arr[i]);
}
maxSum = max(maxSum, dp[i][0]);
maxSum = max(maxSum, dp[i][1]);
maxSum = max(maxSum, dp[i][2]);
}
return maxSum;
}
// Driver Code
int main()
{
int n = 8;
int A[8] = { 2, -1, -18, 3, -1, -39, 5, -2 };
// vector 'arr' contains sum of consecutive
// positive or negative elements.
vector arr;
mergeElements(n, arr, A);
cout << findMaxSum(arr, arr.size());
return 0;
}
Java
// Java program for the above approach
import java.util.*;
class GFG{
// Function to merge alternate elements into groups
// of positive and negative
static Vector mergeElements(int n, Vector arr, int[] A)
{
int i = 0;
int sum = 0;
while (i < n) {
sum = 0;
while (i < n && A[i] >= 0) {
sum += A[i];
i++;
}
if (sum > 0) {
arr.add(sum);
}
sum = 0;
while (i < n && A[i] < 0) {
sum += A[i];
i++;
}
if (sum < 0) {
arr.add(sum);
}
}
return arr;
}
// Function to return the maximum
// after inverting at most 2 elements
static int findMaxSum(Vector arr, int n)
{
int maxSum = 0;
int [][]dp = new int[n][3];
dp[0][0] = Math.max(0, arr.get(0));
dp[0][1] = -1 * arr.get(0);
for (int i = 1; i < n; ++i) {
// dp[i][0] represents sum till ith index
// without inverting any element.
dp[i][0] = Math.max(arr.get(i),
dp[i - 1][0] + arr.get(i));
// dp[i][1] represents sum till ith index
// after inverting one element.
dp[i][1] = Math.max(0, dp[i - 1][0]) - arr.get(i);
if (i >= 1) {
dp[i][1] = Math.max(dp[i][1],
dp[i - 1][1] + arr.get(i));
// dp[i][2] represents sum till ith index
// after inverting two elements.
dp[i][2] = dp[i - 1][1] - arr.get(i);
}
if (i >= 2) {
dp[i][2] = Math.max(dp[i][2],
dp[i - 1][2] + arr.get(i));
}
maxSum = Math.max(maxSum, dp[i][0]);
maxSum = Math.max(maxSum, dp[i][1]);
maxSum = Math.max(maxSum, dp[i][2]);
}
return maxSum;
}
// Driver Code
public static void main(String[] args)
{
int n = 8;
int A[] = { 2, -1, -18, 3, -1, -39, 5, -2 };
// vector 'arr' contains sum of consecutive
// positive or negative elements.
Vector arr = new Vector();
arr = mergeElements(n, arr, A);
System.out.print(findMaxSum(arr, arr.size()));
}
}
// This code is contributed by 29AjayKumar
Python3
# python program for the above approach
INT_MIN = -2147483648
# Function to merge alternate elements into groups
# of positive and negative
def mergeElements(n, arr, A):
i = 0
sum = 0
while (i < n):
sum = 0
while (i < n and A[i] >= 0):
sum += A[i]
i += 1
if (sum > 0):
arr.append(sum)
sum = 0
while (i < n and A[i] < 0):
sum += A[i]
i += 1
if (sum < 0):
arr.append(sum)
# Function to return the maximum
# after inverting at most 2 elements
def findMaxSum(arr, n):
maxSum = 0
dp = [[INT_MIN for _ in range(3)] for _ in range(n)]
dp[0][0] = max(0, arr[0])
dp[0][1] = -1 * arr[0]
for i in range(1, n):
# dp[i][0] represents sum till ith index
# without inverting any element.
dp[i][0] = max(arr[i], dp[i - 1][0] + arr[i])
# dp[i][1] represents sum till ith index
# after inverting one element.
dp[i][1] = max(0, dp[i - 1][0]) - arr[i]
if (i >= 1):
dp[i][1] = max(dp[i][1], dp[i - 1][1] + arr[i])
# dp[i][2] represents sum till ith index
# after inverting two elements.
dp[i][2] = dp[i - 1][1] - arr[i]
if (i >= 2):
dp[i][2] = max(dp[i][2], dp[i - 1][2] + arr[i])
maxSum = max(maxSum, dp[i][0])
maxSum = max(maxSum, dp[i][1])
maxSum = max(maxSum, dp[i][2])
return maxSum
# Driver Code
if __name__ == "__main__":
n = 8
A = [2, -1, -18, 3, -1, -39, 5, -2]
# vector 'arr' contains sum of consecutive
# positive or negative elements.
arr = []
mergeElements(n, arr, A)
print(findMaxSum(arr, len(arr)))
# This code is contributed by rakeshsahni
C#
// C# program for the above approach
using System;
using System.Collections.Generic;
class GFG
{
// Function to merge alternate elements into groups
// of positive and negative
static void mergeElements(int n, List arr, int[] A)
{
int i = 0;
int sum = 0;
while (i < n) {
sum = 0;
while (i < n && A[i] >= 0) {
sum += A[i];
i++;
}
if (sum > 0) {
arr.Add(sum);
}
sum = 0;
while (i < n && A[i] < 0) {
sum += A[i];
i++;
}
if (sum < 0) {
arr.Add(sum);
}
}
}
// Function to return the maximum
// after inverting at most 2 elements
static int findMaxSum(List arr, int n)
{
int maxSum = 0;
int[, ] dp = new int[n, 3];
for (int i = 0; i < n; i++)
for (int j = 0; j < 3; j++)
dp[i, j] = Int32.MinValue;
dp[0, 0] = Math.Max(0, arr[0]);
dp[0, 1] = -1 * arr[0];
for (int i = 1; i < n; ++i) {
// dp[i][0] represents sum till ith index
// without inverting any element.
dp[i, 0]
= Math.Max(arr[i], dp[i - 1, 0] + arr[i]);
// dp[i][1] represents sum till ith index
// after inverting one element.
dp[i, 1] = Math.Max(0, dp[i - 1, 0]) - arr[i];
if (i >= 1) {
dp[i, 1] = Math.Max(dp[i, 1],
dp[i - 1, 1] + arr[i]);
// dp[i][2] represents sum till ith index
// after inverting two elements.
dp[i, 2] = dp[i - 1, 1] - arr[i];
}
if (i >= 2) {
dp[i, 2] = Math.Max(dp[i, 2],
dp[i - 1, 2] + arr[i]);
}
maxSum = Math.Max(maxSum, dp[i, 0]);
maxSum = Math.Max(maxSum, dp[i, 1]);
maxSum = Math.Max(maxSum, dp[i, 2]);
}
return maxSum;
}
// Driver Code
public static void Main()
{
int n = 8;
int[] A = { 2, -1, -18, 3, -1, -39, 5, -2 };
// vector 'arr' contains sum of consecutive
// positive or negative elements.
List arr = new List();
mergeElements(n, arr, A);
Console.WriteLine(findMaxSum(arr, arr.Count));
}
}
// This code is contributed by ukasp.
Javascript
输出
69
时间复杂度:O(N)
辅助空间: O(N)