📌  相关文章
📜  通过将任何子数组的元素的符号反转最多两次来最大化子数组和

📅  最后修改于: 2022-05-13 01:57:50.514000             🧑  作者: Mango

通过将任何子数组的元素的符号反转最多两次来最大化子数组和

给定一个大小为n的数组A ,在应用给定操作最多两次后找到最大子数组和。在一次操作中,选择任意两个索引ij并将索引i到索引j 的所有元素的符号反转,即 i 到 j 范围内的所有正元素变为负,所有负元素变为正。

例子:

方法:这个想法是首先,将所有元素合并到组中。即所有连续的正元素将被求和为一个整数,并将被放置在一个新的数组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)