📜  递减递增交替的任意大小的最大和子序列

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

递减递增交替的任意大小的最大和子序列

给定一个整数数组arr[] ,找到总和最大子序列,其元素首先减少,然后增加,反之亦然,子序列可以在主序列的任何地方开始,不一定在主序列的第一个元素。

例子 :

这个问题是最大和交替子序列问题的扩展。与上一个问题不同,现在我们需要计算交替子序列的最大和,无论它在主序列中的哪个位置,也不管它是以两个元素升序还是两个降序元素开始。

方法:这个问题可以通过动态规划结合回溯来解决。假设,我们有一个包含任意N个元素的数组arr[]

  • 我们可以将每个 arr[i] 元素视为交替序列的终止元素。
  • 可以有许多交替的子序列,其最后一个元素是 arr[i] ,但其中一个肯定是总和最大的序列。
  • 此外,以arr[i]结尾的交替子序列的最大不一定大于以arr[i-1]结尾的交替子序列的最大和。这是根据回溯技术实现算法的基础。
  • 有一个长度为N的数组说maxSum[] ,它将存储在数组arr[]中的每个元素处结束的所有最大和。具体来说,maxSum[i] 将存储以 arr[i] 值结尾的交替子序列的最大和。
  • 我们将使用另一个数组before[]来存储每个交替子序列的最后一个元素之前的值,并具有最大和。

使用以下步骤来实施该方法:

  • 使用循环遍历数组 arr[] 的每个元素。每次我们遍历一个 arr[i] 元素时,我们都会查看它之前的元素:
  • 在每个状态ij ,我们将根据动态规划原理重用任何0 <= j < i的 maxSum[j]:
  • 如果 maxSum[j]不满足上述条件,则可以是两个相等的元素。由于两个相等的元素不被视为交替序列,我们只取其中一个。
  • 或者它可能不是以上任何一种,例如具有两个以上的元素以增加或具有两个以上的元素以递减顺序。

看一下下面的插图,可以清楚地了解这个想法。

下面是上述方法的实现:

C++
// C++ code to implement the above approach
 
#include 
using namespace std;
 
// Function for backtracking
int backtracking(int arr[], int maxSum[], int before[],
                 int N, int root, int bef_root,
                 int bbef_root)
{
    // {root, bef_root} represents state{i, j}
    // bbef_root represent before[before[j]]
    // We ignore the invalid before[j] index
 
    // Base case:
    if (bbef_root == -1)
        return arr[bef_root];
 
    // The case of a subsequence with
    // alternating parts:
    if ((arr[root] > arr[bef_root]
         && arr[bbef_root] > arr[bef_root])
        || (arr[root] < arr[bef_root]
            && arr[bbef_root] < arr[bef_root])) {
        return arr[bef_root] + maxSum[bbef_root];
    }
 
    // case (arr[bef_root] == arr[bbef_root])
    else {
        return backtracking(arr, maxSum, before, N, root,
                            bef_root, before[bbef_root]);
    }
}
 
int maxSumAlternatingSubsequence(int arr[], int N)
{
 
    // Max alternating subsequence sum
    // ending at arr[i].
    int maxSum[N];
 
    // Array to store the index of the element
    // preceding the last element at maxSum[i]
    int before[N];
 
    // Value initialization for arrays:
    fill_n(&maxSum[0], N, 0);
    maxSum[0] = arr[0];
    before[0] = -1;
 
    // Iterate over the array:
    for (int i = 1; i < N; i++)
        for (int j = 0; j < i; j++) {
            int currentMax = 0;
            if ((arr[i] > arr[j]
                 && arr[before[j]] > arr[j])
                || (arr[i] < arr[j]
                    && arr[before[j]] < arr[j])
                || before[j] == -1) {
 
                // Whenever an element is
                // between two smaller elements
                //  or between two larger elements,
                //  it is an alternating sequence.
                //  When the preceding index of j is -1,
                //  we need to treat it explicitly,
                // because -1 is not a valid index.
                currentMax = (arr[i] == arr[j])
                                 ? maxSum[j]
                                 : arr[i] + maxSum[j];
            }
           
            else if (arr[i] == arr[j]) {
                // If arr[i] is equal to arr[j] then
                // only take it once,
                // before[j] cannot be equal to -1.
                currentMax = maxSum[j];
            }
           
            else {
                // Perform backtracking
                // If three adjacent elements
                // are increasing or decreasing.
                currentMax = arr[i]
                             + backtracking(
                                 arr, maxSum, before, N, i,
                                 j, before[before[j]]);
            }
 
            if (currentMax >= maxSum[i]) {
                // Stores the maximum sum and
                // the index preceding
                // the last element
                // at position i of
                // current alternating subsequence
                // after each iteration.
                maxSum[i] = currentMax;
                before[i] = j;
            }
        }
 
    // get max result in array
    return *max_element(maxSum, maxSum + N);
}
 
// Driver code
int main()
{
    int arr[] = { 1, 5, 7, 3, 4, 5 };
    int N = sizeof(arr) / sizeof(int);
 
    // Maximum sum of alternating subsequence
    // of array arr[]
    cout << maxSumAlternatingSubsequence(arr, N)
      << endl;
 
    return 0;
}


Java
// Java code to implement the above approach
import java.io.*;
 
class GFG{
 
// Function for backtracking
static int backtracking(int arr[], int maxSum[],
                        int before[], int N, int root,
                        int bef_root, int bbef_root)
{
     
    // {root, bef_root} represents state{i, j}
    // bbef_root represent before[before[j]]
    // We ignore the invalid before[j] index
 
    // Base case:
    if (bbef_root == -1)
        return arr[bef_root];
 
    // The case of a subsequence with
    // alternating parts:
    if ((arr[root] > arr[bef_root] &&
    arr[bbef_root] > arr[bef_root]) ||
        (arr[root] < arr[bef_root] &&
    arr[bbef_root] < arr[bef_root]))
    {
        return arr[bef_root] + maxSum[bbef_root];
    }
 
    // case (arr[bef_root] == arr[bbef_root])
    else
    {
        return backtracking(arr, maxSum, before, N,
                            root, bef_root,
                            before[bbef_root]);
    }
}
 
static int maxSumAlternatingSubsequence(int arr[],
                                        int N)
{
 
    // Max alternating subsequence sum
    // ending at arr[i].
    int maxSum[] = new int[N];
 
    // Array to store the index of the element
    // preceding the last element at maxSum[i]
    int before[] = new int[N];
 
    // Value initialization for arrays:
    maxSum[0] = arr[0];
    before[0] = -1;
 
    // Iterate over the array:
    for(int i = 1; i < N; i++)
        for(int j = 0; j < i; j++)
        {
            int currentMax = 0;
            if ((arr[i] > arr[j] && before[j] != -1 &&
                   arr[before[j]] > arr[j]) ||
                          (arr[i] < arr[j] && before[j] != -1 &&
                   arr[before[j]] < arr[j]) || before[j] == -1)
            {
                 
                // Whenever an element is
                // between two smaller elements
                // or between two larger elements,
                // it is an alternating sequence.
                // When the preceding index of j is -1,
                // we need to treat it explicitly,
                // because -1 is not a valid index.
                currentMax = (arr[i] == arr[j]) ? maxSum[j] :
                              arr[i] + maxSum[j];
            }
 
            else if (arr[i] == arr[j])
            {
                 
                // If arr[i] is equal to arr[j] then
                // only take it once,
                // before[j] cannot be equal to -1.
                currentMax = maxSum[j];
            }
            else
            {
                 
                // Perform backtracking
                // If three adjacent elements
                // are increasing or decreasing.
                currentMax = arr[i] + backtracking(arr, maxSum,
                                                   before, N, i, j,
                                                   before[before[j]]);
            }
 
            if (currentMax >= maxSum[i])
            {
                 
                // Stores the maximum sum and the index
                // preceding the last element at position
                // i of current alternating subsequence
                // after each iteration.
                maxSum[i] = currentMax;
                before[i] = j;
            }
        }
 
    // get max result in array
    int maxi = 0;
 
    for(int i = 0; i < N; i++)
    {
        maxi = Math.max(maxSum[i], maxi);
    }
    return maxi;
}
 
// Driver code
public static void main(String[] args)
{
    int arr[] = { 1, 5, 7, 3, 4, 5 };
    int N = arr.length;
 
    // Maximum sum of alternating subsequence
    // of array arr[]
    System.out.println(
        maxSumAlternatingSubsequence(arr, N));
}
}
 
// This code is contributed by Potta Lokesh


Python3
# Python code to implement the above approach
 
# Function for backtracking
def backtracking(arr, maxSum, before, N, root, bef_root, bbef_root):
 
    # {root, bef_root} represents state{i, j}
    # bbef_root represent before[before[j]]
    # We ignore the invalid before[j] index
 
    # Base case:
    if (bbef_root == -1):
        return arr[bef_root]
 
    # The case of a subsequence with
    # alternating parts:
    if (arr[root] > arr[bef_root] and arr[bbef_root] > arr[bef_root]) or (arr[root] < arr[bef_root] and arr[bbef_root] < arr[bef_root]):
        return arr[bef_root] + maxSum[bbef_root]
 
    # case (arr[bef_root] == arr[bbef_root])
    else:
        return backtracking(arr, maxSum, before, N,
                            root, bef_root,
                            before[bbef_root])
 
def maxSumAlternatingSubsequence(arr, N):
 
    # Max alternating subsequence sum
    # ending at arr[i].
    maxSum = [0] * N
 
    # Array to store the index of the element
    # preceding the last element at maxSum[i]
    before = [0] * N
 
    # Value initialization for arrays:
    maxSum[0] = arr[0]
    before[0] = -1
 
    # Iterate over the array:
    for i in range(N):
        for j in range(i):
            currentMax = 0
            if (arr[i] > arr[j] and before[j] != -1 and arr[before[j]] > arr[j]) or (arr[i] < arr[j] and before[j] != -1 and arr[before[j]] < arr[j]) or before[j] == -1:
 
                # Whenever an element is
                # between two smaller elements
                # or between two larger elements,
                # it is an alternating sequence.
                # When the preceding index of j is -1,
                # we need to treat it explicitly,
                # because -1 is not a valid index.
                currentMax = maxSum[j] if (
                    arr[i] == arr[j]) else arr[i] + maxSum[j]
 
            elif (arr[i] == arr[j]):
 
                # If arr[i] is equal to arr[j] then
                # only take it once,
                # before[j] cannot be equal to -1.
                currentMax = maxSum[j]
            else:
 
                # Perform backtracking
                # If three adjacent elements
                # are increasing or decreasing.
                currentMax = arr[i] + backtracking(arr, maxSum,
                                                   before, N, i, j,
                                                   before[before[j]])
 
            if (currentMax >= maxSum[i]):
 
                # Stores the maximum sum and the index
                # preceding the last element at position
                # i of current alternating subsequence
                # after each iteration.
                maxSum[i] = currentMax
                before[i] = j
 
    # get max result in array
    maxi = 0
 
    for i in range(N):
        maxi = max(maxSum[i], maxi)
    return maxi
 
# Driver code
arr = [1, 5, 7, 3, 4, 5]
N = len(arr)
 
# Maximum sum of alternating subsequence
# of array arr
print(maxSumAlternatingSubsequence(arr, N))
 
# This code is contributed by gfgking


C#
// C# program for above approach
using System;
class GFG{
 
// Function for backtracking
static int backtracking(int []arr, int []maxSum,
                        int []before, int N, int root,
                        int bef_root, int bbef_root)
{
     
    // {root, bef_root} represents state{i, j}
    // bbef_root represent before[before[j]]
    // We ignore the invalid before[j] index
 
    // Base case:
    if (bbef_root == -1)
        return arr[bef_root];
 
    // The case of a subsequence with
    // alternating parts:
    if ((arr[root] > arr[bef_root] &&
    arr[bbef_root] > arr[bef_root]) ||
        (arr[root] < arr[bef_root] &&
    arr[bbef_root] < arr[bef_root]))
    {
        return arr[bef_root] + maxSum[bbef_root];
    }
 
    // case (arr[bef_root] == arr[bbef_root])
    else
    {
        return backtracking(arr, maxSum, before, N,
                            root, bef_root,
                            before[bbef_root]);
    }
}
 
static int maxSumAlternatingSubsequence(int []arr,
                                        int N)
{
 
    // Max alternating subsequence sum
    // ending at arr[i].
    int []maxSum = new int[N];
 
    // Array to store the index of the element
    // preceding the last element at maxSum[i]
    int []before = new int[N];
 
    // Value initialization for arrays:
    maxSum[0] = arr[0];
    before[0] = -1;
 
    // Iterate over the array:
    for(int i = 1; i < N; i++)
        for(int j = 0; j < i; j++)
        {
            int currentMax = 0;
            if ((arr[i] > arr[j] && before[j] != -1 &&
                   arr[before[j]] > arr[j]) ||
                          (arr[i] < arr[j] && before[j] != -1 &&
                   arr[before[j]] < arr[j]) || before[j] == -1)
            {
                 
                // Whenever an element is
                // between two smaller elements
                // or between two larger elements,
                // it is an alternating sequence.
                // When the preceding index of j is -1,
                // we need to treat it explicitly,
                // because -1 is not a valid index.
                currentMax = (arr[i] == arr[j]) ? maxSum[j] :
                              arr[i] + maxSum[j];
            }
 
            else if (arr[i] == arr[j])
            {
                 
                // If arr[i] is equal to arr[j] then
                // only take it once,
                // before[j] cannot be equal to -1.
                currentMax = maxSum[j];
            }
            else
            {
                 
                // Perform backtracking
                // If three adjacent elements
                // are increasing or decreasing.
                currentMax = arr[i] + backtracking(arr, maxSum,
                                                   before, N, i, j,
                                                   before[before[j]]);
            }
 
            if (currentMax >= maxSum[i])
            {
                 
                // Stores the maximum sum and the index
                // preceding the last element at position
                // i of current alternating subsequence
                // after each iteration.
                maxSum[i] = currentMax;
                before[i] = j;
            }
        }
 
    // get max result in array
    int maxi = 0;
 
    for(int i = 0; i < N; i++)
    {
        maxi = Math.Max(maxSum[i], maxi);
    }
    return maxi;
}
 
// Driver Code
public static void Main()
{
    int []arr = { 1, 5, 7, 3, 4, 5 };
    int N = arr.Length;
 
    // Maximum sum of alternating subsequence
    // of array arr[]
    Console.Write(
        maxSumAlternatingSubsequence(arr, N));
}
}
 
// This code is contributed by Samim Hossain Mondal.


Javascript


输出
21

时间复杂度: O(N 2 ) 其中 N 是数组的长度。
辅助空间: O(N)