Consultas de rango para la subsecuencia de paréntesis correcta más larga

Dada una secuencia de paréntesis o, en otras palabras, una string S de longitud n, que consta de los caracteres ‘(‘ y ‘)’. Encuentre la longitud de la subsecuencia de corchete correcta máxima de la secuencia para un rango de consulta dado. Nota: Una secuencia de corchetes correcta es aquella que tiene pares de corchetes coincidentes o que contiene otra secuencia de corchetes correcta anidada. Por ejemplo,(), (()),()() son una secuencia de paréntesis correcta. Ejemplos:

Input : S = ())(())(())(
        Start Index of Range = 0, 
        End Index of Range = 11
Output : 10
Explanation:  Longest Correct Bracket Subsequence is ()(())(())

Input : S = ())(())(())(
        Start Index of Range = 1, 
        End Index of Range = 2
Output : 0

Los árboles de segmentos se pueden usar para resolver este problema de manera eficiente . En cada Node del árbol de segmentos, almacenamos lo siguiente:

1) a - Number of correctly matched pairs of brackets.
2) b - Number of unused open brackets.  
3) c - Number of unused closed brackets.

(Corchete abierto sin usar: significa que no se puede combinar con ningún corchete de cierre, corchete cerrado sin usar: significa que no se puede combinar con ningún corchete de apertura, por ejemplo, S = )( contiene un paréntesis abierto y cerrado sin usar) Para cada intervalo [L, R], podemos hacer coincidir X número de corchetes abiertos ‘(‘ en el intervalo [L, MID] con corchetes cerrados no utilizados ‘)’ en el intervalo [MID + 1, R] donde X = mínimo (número de no utilizados ‘(‘ en [L, MID], número de no utilizados ‘)’ en [MID + 1, R]) Por lo tanto, X es también el número de pares correctamente construidos por combinación. Entonces, para el intervalo [L, R] 1) El número total de pares coincidentes correctamente se convierte en la suma de los pares coincidentes correctos en el hijo izquierdo y los pares coincidentes correctos en el hijo derecho y el número de combinaciones de ‘(‘ y ‘)’ no utilizados de la izquierda e hijo derecho respectivamente.

a[L, R] = a[L, MID] + a[MID + 1, R] + X

2) El número total de corchetes abiertos no utilizados se convierte en la suma de los corchetes abiertos no utilizados en el elemento secundario izquierdo y los corchetes abiertos no utilizados en el elemento secundario derecho menos X (menos, porque usamos X no utilizados ‘(‘ del elemento secundario izquierdo para coincidir con los elementos no utilizados ‘) del elemento secundario derecho ).

a[L, R] = b[L, MID] + b[MID + 1, R] - X

3) De manera similar, para corchetes cerrados no utilizados, se mantiene la siguiente relación.

a[L, R] = c[L, MID] + c[MID + 1, R] - X

donde a, b y c son las representaciones descritas anteriormente para cada Node en el que se almacenará. A continuación se muestra la implementación del enfoque anterior en C++. 

CPP

/* CPP Program to find the longest correct
bracket subsequence in a given range */
#include <bits/stdc++.h>
using namespace std;
 
/* Declaring Structure for storing
three values in each segment tree node */
struct Node {
    int pairs;
    int open; // unused
    int closed; // unused
 
    Node()
    {
        pairs = open = closed = 0;
    }
};
 
// A utility function to get the middle index from corner indexes.
int getMid(int s, int e) { return s + (e - s) / 2; }
 
// Returns Parent Node after merging its left and right child
Node merge(Node leftChild, Node rightChild)
{
    Node parentNode;
    int minMatched = min(leftChild.open, rightChild.closed);
    parentNode.pairs = leftChild.pairs + rightChild.pairs + minMatched;
    parentNode.open = leftChild.open + rightChild.open - minMatched;
    parentNode.closed = leftChild.closed + rightChild.closed - minMatched;
    return parentNode;
}
 
// A recursive function that constructs Segment Tree
// for string[ss..se]. si is index of current node in
// segment tree st
void constructSTUtil(char str[], int ss, int se, Node* st,
                                                int si)
{
    // If there is one element in string, store it in
    // current node of segment tree and return
    if (ss == se) {
 
        // since it contains one element, pairs
        // will be zero
        st[si].pairs = 0;
 
        // check whether that one element is opening
        // bracket or not
        st[si].open = (str[ss] == '(' ? 1 : 0);
 
        // check whether that one element is closing
        // bracket or not
        st[si].closed = (str[ss] == ')' ? 1 : 0);
 
        return;
    }
 
    // If there are more than one elements, then recur
    // for left and right subtrees and store the relation
    // of values in this node
    int mid = getMid(ss, se);
    constructSTUtil(str, ss, mid, st, si * 2 + 1);
    constructSTUtil(str, mid + 1, se, st, si * 2 + 2);
 
    // Merge left and right child into the Parent Node
    st[si] = merge(st[si * 2 + 1], st[si * 2 + 2]);
}
 
/* Function to construct segment tree from given
string. This function allocates memory for segment
tree and calls constructSTUtil() to fill the
allocated memory */
Node* constructST(char str[], int n)
{
    // Allocate memory for segment tree
 
    // Height of segment tree
    int x = (int)(ceil(log2(n)));
 
    // Maximum size of segment tree
    int max_size = 2 * (int)pow(2, x) - 1;
 
    // Declaring array of structure Allocate memory
    Node* st = new Node[max_size];
 
    // Fill the allocated memory st
    constructSTUtil(str, 0, n - 1, st, 0);
 
    // Return the constructed segment tree
    return st;
}
 
/* A Recursive function to get the desired
Maximum Sum Sub-Array,
The following are parameters of the function-
 
st     --> Pointer to segment tree
si --> Index of the segment tree Node
ss & se --> Starting and ending indexes of the
            segment represented by
                current Node, i.e., tree[index]
qs & qe --> Starting and ending indexes of query range */
Node queryUtil(Node* st, int ss, int se, int qs,
            int qe, int si)
{
    // No overlap
    if (ss > qe || se < qs) {
 
        // returns a Node for out of bounds condition
        Node nullNode;
        return nullNode;
    }
 
    // Complete overlap
    if (ss >= qs && se <= qe) {
        return st[si];
    }
 
    // Partial Overlap Merge results of Left
    // and Right subtrees
    int mid = getMid(ss, se);
    Node left = queryUtil(st, ss, mid, qs, qe, si * 2 + 1);
    Node right = queryUtil(st, mid + 1, se, qs, qe, si * 2 + 2);
 
    // merge left and right subtree query results
    Node res = merge(left, right);
    return res;
}
 
/* Returns the maximum length correct bracket
subsequencebetween start and end
It mainly uses queryUtil(). */
int query(Node* st, int qs, int qe, int n)
{
    Node res = queryUtil(st, 0, n - 1, qs, qe, 0);
 
    // since we are storing numbers pairs
    // and have to return maximum length, hence
    // multiply no of pairs by 2
    return 2 * res.pairs;
}
 
// Driver Code
int main()
{
    char str[] = "())(())(())(";
    int n = strlen(str);
 
    // Build segment tree from given string
    Node* st = constructST(str, n);
 
    int startIndex = 0, endIndex = 11;
    cout << "Maximum Length Correct Bracket"
        " Subsequence between "
        << startIndex << " and " << endIndex << " = "
        << query(st, startIndex, endIndex, n) << endl;
 
    startIndex = 1, endIndex = 2;
    cout << "Maximum Length Correct Bracket"
        " Subsequence between "
        << startIndex << " and " << endIndex << " = "
        << query(st, startIndex, endIndex, n) << endl;
 
    return 0;
}
Producción:

Maximum Length Correct Bracket Subsequence between 0 and 11 = 10
Maximum Length Correct Bracket Subsequence between 1 and 2 = 0

La complejidad del tiempo para cada consulta es O(logN) , donde N es el tamaño de la string.

Espacio Auxiliar: O(N)

Tema relacionado: Árbol de segmentos

Publicación traducida automáticamente

Artículo escrito por Nishant Tanwar 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 *