Subsecuencia de suma máxima de cualquier tamaño que es decreciente-creciente alternativamente

Dada una array de enteros arr[] , encuentre la subsecuencia con suma máxima cuyos elementos primero disminuyen, luego aumentan o viceversa. La subsecuencia puede comenzar en cualquier parte de la secuencia principal, no necesariamente en el primer elemento de la secuencia principal.

Una secuencia {x1, x2, .. xn} es una secuencia alterna si sus elementos satisfacen una de las siguientes relaciones (como se describe en el artículo Subsecuencia alterna más larga )

Dos elementos adyacentes que son iguales no se cuentan como alternos .

x1 < x2 > x3 < x4 > x5 < …. xn 

x1 > x2 < x3 > x4 < x5 > …. xn

 Ejemplos:

Entrada: arr[] = {4, 8, 2, 5, 6, 8}
Salida: 26
Explicación: La subsecuencia alterna con suma máxima es {4, 8, 6, 8}. Suma = 4 + 8 + 6 + 8 = 26

Entrada: arr[] = {0, 1, 1, 1, 3, 2, 5}
Salida: 11
Explicación: La subsecuencia alterna con suma máxima es {1, 3, 2, 5}. Suma = 1 + 3 + 2 + 5 = 11

Entrada: arr[] = {1, 4, 5}
Salida: 9
Explicación: La subsecuencia alterna con suma máxima es {4, 5}. Suma = 4 + 5 = 9

Entrada: arr[] = {1, 0, 1, 0, 0, 3}
Salida: 5
Explicación: La subsecuencia alterna con suma máxima es {1, 0, 1, 0, 3}. Suma = 1 + 0 + 1 + 0 + 3 = 5

Entrada: arr[] = {5, 5}
Salida: 5
Explicación: La subsecuencia alterna con suma máxima es {5}. Suma = 5

 

 

Este problema es una extensión del problema de subsecuencias alternas de suma máxima . A diferencia del problema anterior, ahora necesitamos calcular la suma máxima de la subsecuencia alterna independientemente de dónde se encuentre en la secuencia principal , e independientemente de si comienza con dos elementos ascendentes o descendentes .

Enfoque: Este problema se puede resolver mediante Programación Dinámica combinada con Backtracking . Supongamos que tenemos una array arr[] con cualquier N elementos. 

  • Podemos considerar cada elemento arr[i] como un elemento terminal de una secuencia alterna.
  • Puede haber muchas subsecuencias alternas cuyo último elemento sea arr[i] , pero seguramente una de ellas es la secuencia con mayor suma.
  • Además, la suma máxima de las subsecuencias alternas que terminan en arr[i] no es necesariamente mayor que la suma máxima de las subsecuencias alternas que terminan en arr[i-1]. Y esta es la base para implementar el algoritmo según la técnica de Backtracking .
  • Haga que una array diga maxSum[] de longitud N que almacenará todas las sumas máximas que terminan en cada elemento de la array arr[] . Específicamente, maxSum[i] almacenará la suma máxima de la subsecuencia alterna que termina en el valor arr[i].
  • Usaremos otra array before[] para almacenar el valor que precede al último elemento de cada subsecuencia alterna con suma máxima.

Por ejemplo , un arreglo arr[] = {1, 5, 7, 3, 4, 5} tendrá una subsecuencia alterna {5, 7, 3, 4} cuya suma máxima es 5 + 7 + 3 + 4 = 19. 
La subsecuencia {5, 7, 3, 4} termina en el valor 4, que tiene el índice 4 en el arreglo arr[].  
Entonces tenemos arr[4] = 4, maxSum[4] = 19, before[4] = 3 (porque arr[3] = 3). 
Esos valores se calcularán y guardarán en dos arrays maxSum[] y before[] durante el cálculo y se pueden reutilizar según sea necesario.

Use los siguientes pasos para implementar el enfoque:

  • Utilice un bucle para iterar a través de cada elemento de la array arr[]. Cada vez que atravesamos un elemento arr[i], observamos los elementos que lo preceden:

i Recorrido de bucle de 1 a N-1 (no es necesario comenzar en la posición 0, porque ese es el caso base):
        j Recorrido de bucle de 0 a i-1 :

  • En cada estado i y j , reutilizaremos cualquier maxSum[j] con 0 <= j < i de acuerdo con el principio de Programación Dinámica:

si:
        (arr[i] > arr[j] && arr[antes de [j]] > arr[j]) 
                            o
        (arr[i] < arr[j] && arr[antes de [j]] < arr[j] )

entonces:
        suma = arr[i] + maxSuma[j] 

  • Si maxSum[j] no cumple la condición anterior, pueden ser dos elementos iguales . Dado que dos elementos iguales no se tratan como una secuencia alterna, solo tomamos uno de ellos.

si: 
        arr[i] == arr[j]

entonces:
        suma = maxSuma[j]

  • O puede no ser ninguno de los anteriores, como tener más de dos elementos en orden creciente o tener más de dos elementos en orden decreciente.

Ejemplo {1, 5, 7, 3, 4, 5 }. Supongamos que estamos en i = 5, j = 4

  • Entonces before[4] es el tercer elemento , y (arr[before[j]], arr[j], arr[i]) = (arr[before[4]], arr[4], arr[5 ]) = (arr[3], arr[4], arr[5]) = (3, 4, 5).
  • La anterior no es una subsecuencia alterna válida , lo que significa que before[j] no es el índice de un valor válido.
  • Veremos el elemento anterior de arr[before[j]] en su secuencia alterna: before[before[j]] = before[3] = 2, and arr[2] with arr[4] and arr[5] formar una subsecuencia válida (7, 4, 5).
  • Entonces obtenemos un valor de arr[5] + arr[4] + maxSum[2], que es la suma final del estado {i = 5, j = 4}.
  • Necesitamos compararlo con otros estados {i y j} (como {i = 5, j = 3}, {i = 5, j = 2}…) para obtener el resultado final de maxSum[5].
  • Luego guarde j en before[5] si precede a arr[5] y ayuda a arr[5] a formar una subsecuencia válida con una suma máxima en el estado 5.

Eche un vistazo a la ilustración a continuación para tener una idea clara.

índice      : 0 1 2 3 4 5 || N = 6
arr[]      : 1, 5, 7, 3, 4, 5

——————————————————————————————————-

maxSum[0] :    0 0 0 0 0 = 1 caso base
antes de [-1] :   -1  _ _ _ _ _

maxSum[1] : 1   0 0 0 0 = 6 porque 1 + 5
antes[1] : -1   _ _ _ _

maxSum[2]: 1 6 12  0 0 0 = 12 porque 1, 5, 7 no es una subsecuencia alterna , y solo 5 y 7 
before[2]: -1 0   1  _ _ _ es válido, usamos el retroceso en el índice 2 por 
lo que pasaremos por la siguiente subsecuencia: {1, 7}, {5, 7}. Tenemos {5, 7} porque before[1] es el índice 0, 
continuamos encontrando valor en before[before[1]] = -1, cuyo valor es 0, entonces 0 + 5 + 7 = 12 > 1 + 7 .

maxSum[3] : 1 6 12 15  0 0 = 15 porque 5, 7, 3 es una subsecuencia alterna válida, 
before[3] : -1 0 1   2  _ _ so 3 + max(maxSum[2], maxSum[1] , maxSuma[0]) = 3 + 12.

maxSum[4] : 1 6 12 15 19  0 = 19 porque 5, 7, 3, 4 es una subsecuencia alterna válida,
before[4] : -1 0 1 2   3  _ entonces 4 + max(maxSum[3], maxSum[ 2],… maxSuma[0]) = 4 + 15.

maxSum[5] : 1 6 12 15 19 21   = 21 , arr[5] no puede ser el siguiente elemento de maxSum[4] porque 3, 4, 5
before[5] : -1 0 1 2 3   2 no está alternando subsecuencia Así que necesitamos usar el retroceso aquí. 
Trataremos el valor 3 como un valor inválido para la subsecuencia alterna que termina en arr[5]. 
Necesitamos encontrar el elemento anterior de before[arr[4]] en la suma de maxSum[4] recursivamente, 
es decir, el índice 2. Ahora 7, 4, 5 han formado una subsecuencia alterna válida. 
Entonces tenemos 5 + max(backtracking(index 4), maxSum[3], maxSum[2],…) = 5 + 16 (porque 4 + 7 + 5)
Entonces, la suma máxima final de la subsecuencia alterna de arr es el elemento max de la array «maxSum».

Salida: 21

A continuación se muestra la implementación del enfoque anterior:

C++

// C++ code to implement the above approach
 
#include <bits/stdc++.h>
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

<script>
// javascript code to implement the above approach
 
// Function for backtracking
function 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] &&
    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]);
    }
}
 
function maxSumAlternatingSubsequence(arr,N)
{
 
    // Max alternating subsequence sum
    // ending at arr[i].
    var maxSum = Array.from({length: N}, (_, i) => 0);
 
    // Array to store the index of the element
    // preceding the last element at maxSum[i]
    var before = Array.from({length: N}, (_, i) => 0);
 
    // Value initialization for arrays:
    maxSum[0] = arr[0];
    before[0] = -1;
 
    // Iterate over the array:
    for(var i = 1; i < N; i++)
        for(var j = 0; j < i; j++)
        {
            var 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
    var maxi = 0;
 
    for(var i = 0; i < N; i++)
    {
        maxi = Math.max(maxSum[i], maxi);
    }
    return maxi;
}
 
// Driver code
var arr = [ 1, 5, 7, 3, 4, 5 ];
var N = arr.length;
 
// Maximum sum of alternating subsequence
// of array arr
document.write(
maxSumAlternatingSubsequence(arr, N));
 
// This code is contributed by 29AjayKumar
</script>
Producción

21

Complejidad de tiempo : O(N 2 ) donde N es la longitud de la array.
Espacio Auxiliar: O(N)

Publicación traducida automáticamente

Artículo escrito por nguyenhanhkhoa01012000 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *