Salta al contenuto
Note per Studenti Esercizio - sottosequenza quasi palindroma di lunghezza massima (compito dell'8 luglio 2024, es. 2)

Esercizio - sottosequenza quasi palindroma di lunghezza massima (compito dell'8 luglio 2024, es. 2)

Fonte: compito di Algoritmi per l'Ingegneria, Ing. Informatica UniPD, 8 luglio 2024, seconda parte, esercizio 2 (17 punti).

Testo

Una stringa di interi Z=⟨z1,z2,…,zm⟩∈Z∗Z = \langle z_1, z_2, \dots, z_m \rangle \in \mathbb{Z}^* si dice quasi palindroma se, per ogni h=0,1,…,m−1h = 0, 1, \dots, m - 1, si ha ∣z1+h−zm−h∣≤1|z_{1+h} - z_{m-h}| \le 1. Data una stringa X=⟨x1,x2,…,xn⟩∈Z∗X = \langle x_1, x_2, \dots, x_n \rangle \in \mathbb{Z}^*, il problema della Longest Quasi Palindrome Subsequence (LQPS) consiste nel determinare la massima lunghezza di una sottosequenza quasi palindroma di XX.

  • (a) [7 punti] Si formuli una proprietà di sottostruttura ottima per il problema sullo spazio delle sottostringhe IX={Xi..j:1≤i≤j≤n}\mathcal{I}_X = \{X_{i..j} : 1 \le i \le j \le n\} della stringa XX e se ne provi la correttezza.
  • (b) [5 punti] Sulla base della proprietà provata al punto (a), si derivi una ricorrenza sulla lunghezza della LQPS.
  • (c) [5 punti] Si scriva lo pseudocodice bottom-up associato al calcolo della ricorrenza sviluppata al punto precedente e se ne valuti la correttezza e la complessità, in funzione del numero di addizioni e sottrazioni tra i caratteri della stringa.

Soluzione

Idea

Una stringa quasi palindroma è una palindroma in cui "uguale" è sostituito da "differisce al più di 11": le coppie simmetriche (z1,zm)(z_1, z_m), (z2,zm−1)(z_2, z_{m-1}), ... devono essere vicine. Per esempio ⟨3,5,4,4,2⟩\langle 3, 5, 4, 4, 2 \rangle lo è: ∣3−2∣=1|3 - 2| = 1, ∣5−4∣=1|5 - 4| = 1 e il centro 44 è confrontato con sé stesso. È il problema della sottosequenza palindroma più lunga (Allineamento di stringhe e sottosequenza palindroma più lungadue problemi di DP su stringhe con la stessa struttura della LCS. Allineamento ottimo di due stringhe di DNA con matrice di score S e penalità di gap g: C(i,j) = max{C(i-1,j-1) + s(x_i,y_j), C(i-1,j) + g, C(i,j-1) + g}, C(i,0) = i g, C(0,j) = j g; Theta(mn) tempo, spazio Theta(min{m,n}) con un solo vettore se serve solo il costo. Sottosequenza palindroma più lunga (LPS) sullo spazio delle sottostringhe X_(i..j): p(i,j) = 2 + p(i+1,j-1) se x_i = x_j, altrimenti max{p(i+1,j), p(i,j-1)}; scansione per diagonali, n(n-1)/2 confronti.Allineamento di stringhe e sottosequenza palindroma più lunga →) con una relazione di "compatibilità" tra gli estremi più larga dell'uguaglianza. Come per quella, si tolgono i caratteri dai due estremi, quindi lo spazio dei sottoproblemi è quello delle sottostringhe Xi..jX_{i..j} (Θ(n2)\Theta(n^2)).

Una stringa di un solo carattere è sempre quasi palindroma, e una di due caratteri lo è se e solo se i due differiscono di al più 11.

(a) Proprietà di sottostruttura ottima

Proprietà. Per ogni 1≤i≤j≤n1 \le i \le j \le n esiste una Z=⟨z1,…,zk⟩Z = \langle z_1, \dots, z_k \rangle, LQPS di Xi..jX_{i..j}, tale che:

  1. se i=ji = j: Z=⟨xi⟩Z = \langle x_i \rangle;
  2. se j=i+1j = i + 1 e ∣xi−xj∣≤1|x_i - x_j| \le 1: Z=⟨xi,xj⟩Z = \langle x_i, x_j \rangle;
  3. se j=i+1j = i + 1 e ∣xi−xj∣>1|x_i - x_j| > 1: Z=⟨xi⟩Z = \langle x_i \rangle;
  4. se j>i+1j > i + 1 e ∣xi−xj∣≤1|x_i - x_j| \le 1: z1=xiz_1 = x_i, zk=xjz_k = x_j e Z2..k−1Z_{2..k-1} è una LQPS di Xi+1..j−1X_{i+1..j-1};
  5. altrimenti (j>i+1j > i + 1 e ∣xi−xj∣>1|x_i - x_j| > 1): ZZ è la più lunga tra una LQPS di Xi..j−1X_{i..j-1} e una LQPS di Xi+1..jX_{i+1..j}.

(Come nei problemi analoghi, il punto 4 dice che esiste una LQPS con estremi xix_i e xjx_j, non che tutte le LQPS li abbiano: basta per un algoritmo corretto.)

Dimostrazione. I punti 1, 2 e 3 sono banali (una stringa di un carattere è quasi palindroma; una di due caratteri lo è se e solo se la differenza è al più 11).

Punto 4. Sia j>i+1j > i + 1 e ∣xi−xj∣≤1|x_i - x_j| \le 1. Sia Z′=⟨xj1,…,xjk⟩Z' = \langle x_{j_1}, \dots, x_{j_k} \rangle una LQPS qualsiasi di Xi..jX_{i..j}, con i≤j1<⋯<jk≤ji \le j_1 < \dots < j_k \le j. Poiché ⟨xi,xj⟩\langle x_i, x_j \rangle è quasi palindroma, k≥2k \ge 2.

  • Non possono valere insieme j1>ij_1 > i e jk<jj_k < j: altrimenti ⟨xi,Z′,xj⟩\langle x_i, Z', x_j \rangle sarebbe una sottosequenza di Xi..jX_{i..j} (indici i<j1i < j_1 e jk<jj_k < j), quasi palindroma (le coppie interne sono quelle di Z′Z' e la coppia esterna (xi,xj)(x_i, x_j) è compatibile) e più lunga di Z′Z', contro la massimalità. Quindi j1=ij_1 = i oppure jk=jj_k = j.
  • Se j1=ij_1 = i e jk<jj_k < j, si sostituisce l'ultimo carattere di Z′Z' con xjx_j (indice j>jk−1j > j_{k-1}); se j1>ij_1 > i e jk=jj_k = j, si sostituisce il primo con xix_i. La stringa ZZ ottenuta ha la stessa lunghezza kk, è sottosequenza di Xi..jX_{i..j}, e resta quasi palindroma: le coppie interne non cambiano e la coppia esterna è ora (xi,xj)(x_i, x_j), compatibile. Quindi ZZ è una LQPS con z1=xiz_1 = x_i e zk=xjz_k = x_j (se j1=ij_1 = i e jk=jj_k = j non occorre sostituire nulla).
  • Z2..k−1Z_{2..k-1} è quasi palindroma ed è sottosequenza di Xi+1..j−1X_{i+1..j-1}. Se non ne fosse una LQPS, sostituendola con una LQPS WW di Xi+1..j−1X_{i+1..j-1} (cut-and-paste) si otterrebbe ⟨xi,W,xj⟩\langle x_i, W, x_j \rangle, quasi palindroma e più lunga di ZZ: contraddizione.

Punto 5. Sia Z′Z' una LQPS qualsiasi di Xi..jX_{i..j} con j>i+1j > i + 1 e ∣xi−xj∣>1|x_i - x_j| > 1. Se Z′Z' usasse entrambi gli indici ii e jj come primo e ultimo elemento (con k≥2k \ge 2), la coppia esterna (xi,xj)(x_i, x_j) violerebbe la condizione. Quindi j1>ij_1 > i oppure jk<jj_k < j (se k=1k = 1 vale jk<jj_k < j oppure j1>ij_1 > i perché i<ji < j). Nel primo caso Z′Z' è una sottosequenza quasi palindroma di Xi+1..jX_{i+1..j}, nel secondo di Xi..j−1X_{i..j-1}; in entrambi deve essere la migliore, altrimenti con il cut-and-paste se ne troverebbe una più lunga anche in Xi..jX_{i..j}. Poiché le LQPS delle due sottostringhe sono anche sottosequenze quasi palindrome di Xi..jX_{i..j}, Z′Z' è la più lunga delle due. □\square

(b) Ricorrenza

Sia ℓ(i,j)\ell(i, j) la lunghezza di una LQPS di Xi..jX_{i..j}, per 1≤i≤j≤n1 \le i \le j \le n. Dalla proprietà:

ℓ(i,j)={1i=j2(i=j−1) ∧ (∣xi−xj∣≤1)1(i=j−1) ∧ (∣xi−xj∣>1)2+ℓ(i+1,j−1)(i<j−1) ∧ (∣xi−xj∣≤1)max⁡{ℓ(i,j−1), ℓ(i+1,j)}altrimenti\ell(i, j) = \begin{cases} 1 & i = j \\ 2 & (i = j - 1) \ \land \ (|x_i - x_j| \le 1) \\ 1 & (i = j - 1) \ \land \ (|x_i - x_j| > 1) \\ 2 + \ell(i+1, j-1) & (i < j - 1) \ \land \ (|x_i - x_j| \le 1) \\ \max\{\ell(i, j-1),\ \ell(i+1, j)\} & \text{altrimenti} \end{cases}

La risposta è ℓ(1,n)\ell(1, n).

(c) Algoritmo bottom-up

La cella (i,j)(i, j) dipende da (i+1,j−1)(i+1, j-1), (i,j−1)(i, j-1) e (i+1,j)(i+1, j), relative a sottostringhe più corte (di lunghezza ℓ−2\ell - 2, ℓ−1\ell - 1, ℓ−1\ell - 1 se ℓ=j−i+1\ell = j - i + 1): una scansione per diagonali di lunghezza crescente nel triangolo superiore della tabella L[1..n,1..n]L[1..n, 1..n] è coerente. (Anche "righe dalla nn alla 11" e "colonne con righe decrescenti" lo sono.)

LQPS(X)
  n <- |X|                                   { X = <x_1, ..., x_n> }
  for i <- 1 to n-1 do
    L[i, i] <- 1
    if |x_i - x_{i+1}| <= 1 then L[i, i+1] <- 2
    else L[i, i+1] <- 1
  L[n, n] <- 1                               { casi base: diagonali l = 1 e l = 2 }
  for l <- 3 to n do
    for i <- 1 to n-l+1 do
      j <- i + l - 1                         { sottostringa X_{i..j} }
      if |x_i - x_j| <= 1 then L[i, j] <- 2 + L[i+1, j-1]
      else L[i, j] <- MAX(L[i, j-1], L[i+1, j])
  return L[1, n]

Correttezza. Per induzione sulla lunghezza della sottostringa: le prime due diagonali realizzano i casi base della ricorrenza; per ℓ≥3\ell \ge 3 le tre celle da cui dipende (i,j)(i, j) sono su diagonali già complete e corrette per ipotesi induttiva, e l'assegnamento implementa il caso corrispondente della ricorrenza, che è corretta per la proprietà (a). Per n=1n = 1 si restituisce L[1,1]=1L[1,1] = 1. L'algoritmo è stato confrontato con l'enumerazione di tutte le sottosequenze su 600600 vettori casuali di interi piccoli (lunghezza fino a 1010): stesso risultato in tutti i casi.

Esempio. X=⟨3,5,4,8,4,2,6⟩X = \langle 3, 5, 4, 8, 4, 2, 6 \rangle (n=7n = 7). Tabella L[i,j]L[i, j] (triangolo superiore):

1: 3 2: 5 3: 4 4: 8 5: 4 6: 2 7: 6
1: 3 1 1 3 3 4 5 5
2: 5 1 2 2 3 3 5
3: 4 1 1 3 3 3
4: 8 1 1 1 1
5: 4 1 1 1
6: 2 1 1
7: 6 1

Alcune celle: L[3,4]L[3,4]: ∣4−8∣=4>1|4 - 8| = 4 > 1, quindi max⁡{L[3,3],L[4,4]}=1\max\{L[3,3], L[4,4]\} = 1. L[2,5]L[2,5]: ∣5−4∣=1≤1|5 - 4| = 1 \le 1, quindi 2+L[3,4]=32 + L[3,4] = 3. L[1,6]L[1,6]: ∣3−2∣=1|3 - 2| = 1, quindi 2+L[2,5]=52 + L[2,5] = 5. L[1,7]L[1,7]: ∣3−6∣=3>1|3 - 6| = 3 > 1, quindi max⁡{L[1,6],L[2,7]}=max⁡{5,5}=5\max\{L[1,6], L[2,7]\} = \max\{5, 5\} = 5. Una LQPS di lunghezza 55 è ⟨3,5,4,4,2⟩\langle 3, 5, 4, 4, 2 \rangle, con indici 1,2,3,5,61, 2, 3, 5, 6 (coppie (3,2)(3,2), (5,4)(5,4) e centro 44).

Complessità. Si fa una sola sottrazione tra caratteri (il valore assoluto e il confronto con 11 non si contano) per ogni sottostringa di lunghezza ℓ≥2\ell \ge 2, cioè una per ogni diagonale ℓ=2,…,n\ell = 2, \dots, n e ogni cella:

T(n)=∑ℓ=2n∑i=1n−ℓ+11=∑ℓ=2n(n−ℓ+1)=∑ℓ′=1n−1ℓ′=n(n−1)2=Θ(n2).T(n) = \sum_{\ell=2}^{n} \sum_{i=1}^{n-\ell+1} 1 = \sum_{\ell=2}^{n} (n - \ell + 1) = \sum_{\ell'=1}^{n-1} \ell' = \frac{n(n-1)}{2} = \Theta(n^2).

(Nella penultima uguaglianza si pone ℓ′=n−ℓ+1\ell' = n - \ell + 1, che va da n−1n - 1 a 11.) Per l'esempio n=7n = 7: 2121 sottrazioni. Con le somme 2+L[i+1,j−1]2 + L[i+1, j-1] sui valori della tabella il conto resta quadratico; il numero di addizioni e sottrazioni tra i caratteri della stringa è quello sopra. Lo spazio è Θ(n2)\Theta(n^2), riducibile a lineare con tre vettori se serve solo la lunghezza.

Versione ripasso

Testo. ZZ è quasi palindroma se ∣z1+h−zm−h∣≤1|z_{1+h} - z_{m-h}| \le 1 per 0≤h≤m−10 \le h \le m-1. LQPS(X)(X) = massima lunghezza di una sottosequenza quasi palindroma di X∈Z∗X \in \mathbb{Z}^*. (a) [7 punti] sottostruttura ottima sulle sottostringhe Xi..jX_{i..j} con prova; (b) [5 punti] ricorrenza; (c) [5 punti] pseudocodice bottom-up, correttezza e complessità in numero di addizioni e sottrazioni tra i caratteri.

LQPS(X)
  n <- |X|
  for i <- 1 to n-1 do
    L[i,i] <- 1
    if |x_i - x_{i+1}| <= 1 then L[i,i+1] <- 2 else L[i,i+1] <- 1
  L[n,n] <- 1
  for l <- 3 to n do for i <- 1 to n-l+1 do
    j <- i + l - 1
    if |x_i - x_j| <= 1 then L[i,j] <- 2 + L[i+1,j-1]
    else L[i,j] <- MAX(L[i,j-1], L[i+1,j])
  return L[1,n]
  • Correttezza: induzione sulla lunghezza; (i,j)(i,j) dipende da diagonali ℓ−2\ell - 2 e ℓ−1\ell - 1. Altre scansioni valide: righe da nn a 11, colonne con righe decrescenti.
  • Esempio X=⟨3,5,4,8,4,2,6⟩X = \langle 3,5,4,8,4,2,6 \rangle: L[3,4]=1L[3,4] = 1, L[2,5]=2+1=3L[2,5] = 2 + 1 = 3, L[1,6]=2+3=5L[1,6] = 2 + 3 = 5, L[1,7]=max⁡{5,5}=5L[1,7] = \max\{5,5\} = 5; LQPS ⟨3,5,4,4,2⟩\langle 3,5,4,4,2 \rangle (indici 1,2,3,5,61,2,3,5,6).
  • Costo: una sottrazione per ogni i<ji < j: T(n)=∑ℓ=2n(n−ℓ+1)=n(n−1)2T(n) = \sum_{\ell=2}^{n}(n-\ell+1) = \frac{n(n-1)}{2} (2121 per n=7n = 7).
  • Errori tipici: usare xi=xjx_i = x_j invece di ∣xi−xj∣≤1|x_i - x_j| \le 1; porre L[i,i+1]=2L[i,i+1] = 2 senza controllare la compatibilità; scansione per righe crescenti; contare anche le somme sui valori della tabella tra "addizioni tra i caratteri".

Teoria collegata