Algorithm Search⌘K

Proofs: Hirschberg's algorithm

These are the human proofs of Hirschberg's algorithm, at full length.

Hirschberg's algorithm returns a longest common subsequence full

This proof shows: correctness.

We use the pseudocode of the page. Write lcs(U,V)\mathrm{lcs}(U, V) for the length of a longest common subsequence of UU and VV, URU^R for the reverse of UU, X[a…b]=xa⋯xbX[a \ldots b] = x_a \cdots x_b and Y[a…b]=ya⋯ybY[a \ldots b] = y_a \cdots y_b, both empty if a>ba > b.

Lemma 1 (LCS-ROW). LCS-ROW(X,Y)(X, Y) returns RR with R[j]=lcs(X,Y[1…j])R[j] = \mathrm{lcs}(X, Y[1 \ldots j]) for 0≤j≤n0 \le j \le n.

Proof. Let L(i,j)=lcs(X[1…i],Y[1…j])L(i, j) = \mathrm{lcs}(X[1 \ldots i], Y[1 \ldots j]). We show by induction on ii that after ii rounds of the loop of line L9, R[j]=L(i,j)R[j] = L(i, j) for all jj. For i=0i = 0, line L8 sets R[j]=0=L(0,j)R[j] = 0 = L(0, j).

Let i≥1i \ge 1 and assume R[j]=L(i−1,j)R[j] = L(i - 1, j) for all jj before round ii. Inside the round we show by induction on jj that, before the iteration jj of line L11, R[0…j−1]R[0 \ldots j - 1] holds L(i,0),…,L(i,j−1)L(i, 0), \ldots, L(i, j - 1), R[j…n]R[j \ldots n] holds L(i−1,j),…,L(i−1,n)L(i - 1, j), \ldots, L(i - 1, n), and diag=L(i−1,j−1)\mathrm{diag} = L(i - 1, j - 1). Before j=1j = 1 this holds: R[0]=0=L(i,0)R[0] = 0 = L(i, 0) is never written, the rest of RR is the old row, and line L10 sets diag=0=L(i−1,0)\mathrm{diag} = 0 = L(i - 1, 0). In iteration jj, line L12 sets up=L(i−1,j)\mathrm{up} = L(i - 1, j), and line L13 writes L(i−1,j−1)+1L(i - 1, j - 1) + 1 if xi=yjx_i = y_j, and max⁡(L(i−1,j),L(i,j−1))\max(L(i - 1, j), L(i, j - 1)) if not. By the LCS recurrence (the corollary of the optimal substructure theorem) this is L(i,j)L(i, j). Line L14 sets diag=L(i−1,j)\mathrm{diag} = L(i - 1, j), which is the value needed for j+1j + 1. After j=nj = n the whole row holds L(i,⋅)L(i, \cdot). □\square

Lemma 2 (reversal). ZZ is a common subsequence of UU and VV if and only if ZRZ^R is a common subsequence of URU^R and VRV^R. So lcs(U,V)=lcs(UR,VR)\mathrm{lcs}(U, V) = \mathrm{lcs}(U^R, V^R).

Proof. If Z=ui1⋯uikZ = u_{i_1} \cdots u_{i_k} with i1<⋯<iki_1 < \cdots < i_k, then ZRZ^R is the subsequence of URU^R at the positions ∣U∣+1−ik<⋯<∣U∣+1−i1|U| + 1 - i_k < \cdots < |U| + 1 - i_1. The same holds for VV, and the converse is the same statement applied to ZRZ^R. □\square

By Lemmas 1 and 2, after lines L4 and L5 of a call with m≥2m \ge 2,

F[j]=lcs(X[1…h],Y[1…j]),B[n−j]=lcs(X[h+1…m]R,Y[j+1…n]R)=lcs(X[h+1…m],Y[j+1…n]),F[j] = \mathrm{lcs}(X[1 \ldots h], Y[1 \ldots j]), \qquad B[n - j] = \mathrm{lcs}(X[h+1 \ldots m]^R, Y[j+1 \ldots n]^R) = \mathrm{lcs}(X[h+1 \ldots m], Y[j+1 \ldots n]),

since the first n−jn - j items of YRY^R are Y[j+1…n]RY[j+1 \ldots n]^R.

Lemma 3 (split). For each 0≤h≤m0 \le h \le m,

lcs(X,Y)=max⁡0≤j≤n(lcs(X[1…h],Y[1…j])+lcs(X[h+1…m],Y[j+1…n])).\mathrm{lcs}(X, Y) = \max_{0 \le j \le n} \big( \mathrm{lcs}(X[1 \ldots h], Y[1 \ldots j]) + \mathrm{lcs}(X[h+1 \ldots m], Y[j+1 \ldots n]) \big).

Proof. (≥\ge) Fix jj. Let Z1Z_1 be an LCS of X[1…h]X[1 \ldots h] and Y[1…j]Y[1 \ldots j] and Z2Z_2 an LCS of X[h+1…m]X[h+1 \ldots m] and Y[j+1…n]Y[j+1 \ldots n]. The positions of Z1Z_1 in XX are at most hh and those of Z2Z_2 are above hh, and the same holds in YY with jj. So Z1Z2Z_1 Z_2 is a common subsequence of XX and YY, of length ∣Z1∣+∣Z2∣|Z_1| + |Z_2|.

(≤\le) Let ZZ be an LCS of XX and YY, of length ℓ\ell, with positions i1<⋯<iℓi_1 < \cdots < i_\ell in XX and j1<⋯<jℓj_1 < \cdots < j_\ell in YY, where xit=yjt=ztx_{i_t} = y_{j_t} = z_t. Let ss be the number of tt with it≤hi_t \le h, so i1,…,is≤h<is+1,…,iℓi_1, \ldots, i_s \le h < i_{s+1}, \ldots, i_\ell. Let j=jsj = j_s if s≥1s \ge 1 and j=0j = 0 if s=0s = 0. Then z1⋯zsz_1 \cdots z_s is a common subsequence of X[1…h]X[1 \ldots h] and Y[1…j]Y[1 \ldots j], and zs+1⋯zℓz_{s+1} \cdots z_\ell is a common subsequence of X[h+1…m]X[h+1 \ldots m] and Y[j+1…n]Y[j+1 \ldots n], since js+1>js=jj_{s+1} > j_s = j. So ℓ=s+(ℓ−s)\ell = s + (\ell - s) is at most the term of the maximum for this jj. □\square

Theorem. For all XX and YY, HIRSCHBERG(X,Y)(X, Y) returns a common subsequence of XX and YY of length lcs(X,Y)\mathrm{lcs}(X, Y).

Proof. Induction on mm.

Base. If m=0m = 0 or n=0n = 0, the only common subsequence is empty, and line L1 returns it. If m=1m = 1 and n≥1n \ge 1, lcs(X,Y)\mathrm{lcs}(X, Y) is 1 if x1x_1 occurs in YY and 0 otherwise, and line L2 returns ⟨x1⟩\langle x_1 \rangle or the empty sequence, which are common subsequences of these lengths.

Step. Let m≥2m \ge 2, so 1≤h=⌊m/2⌋<m1 \le h = \lfloor m/2 \rfloor < m and both halves of XX are shorter than XX. By Lemmas 1 to 3, line L6 picks kk with

F[k]+B[n−k]=max⁡j(F[j]+B[n−j])=lcs(X,Y).F[k] + B[n - k] = \max_j \big( F[j] + B[n - j] \big) = \mathrm{lcs}(X, Y).

By the induction hypothesis, the first call of line L7 returns a common subsequence Z1Z_1 of X[1…h]X[1 \ldots h] and Y[1…k]Y[1 \ldots k] of length F[k]F[k], and the second returns a common subsequence Z2Z_2 of X[h+1…m]X[h+1 \ldots m] and Y[k+1…n]Y[k+1 \ldots n] of length B[n−k]B[n - k]. As in the (≥\ge) part of Lemma 3, Z1Z2Z_1 Z_2 is a common subsequence of XX and YY. Its length is F[k]+B[n−k]=lcs(X,Y)F[k] + B[n - k] = \mathrm{lcs}(X, Y). □\square

Termination. Each recursive call has a shorter first sequence (h<mh < m and m−h<mm - h < m for m≥2m \ge 2), so the recursion ends.

Cost. Let C(m,n)C(m, n) be the number of cells that LCS-ROW fills in a call on lengths mm and nn, and let c(1)=0c(1) = 0 and c(m)=m+c(⌈m/2⌉)c(m) = m + c(\lceil m/2 \rceil) for m≥2m \ge 2. Then cc is non-decreasing and C(m,n)≤c(m) nC(m, n) \le c(m) \, n. For m≤1m \le 1, C=0C = 0. For m≥2m \ge 2, the call fills hn+(m−h)n=mnhn + (m - h)n = mn cells and

C(m,n)≤mn+c(h)k+c(m−h)(n−k)≤mn+c(⌈m/2⌉)n=c(m)n,C(m, n) \le mn + c(h) k + c(m - h)(n - k) \le mn + c(\lceil m/2 \rceil) n = c(m) n,

because h,m−h≤⌈m/2⌉h, m - h \le \lceil m/2 \rceil. Unrolling, c(m)≤m+⌈m/2⌉+⌈m/4⌉+⋯c(m) \le m + \lceil m/2 \rceil + \lceil m/4 \rceil + \cdots, and since ⌈m/2t⌉<m/2t+1\lceil m/2^t \rceil < m/2^t + 1 and the sum has at most ⌈log⁡2m⌉\lceil \log_2 m \rceil terms, c(m)<2m+⌈log⁡2m⌉c(m) < 2m + \lceil \log_2 m \rceil. So the algorithm fills fewer than (2m+⌈log⁡2m⌉)n(2m + \lceil \log_2 m \rceil) n cells, and at least the mnmn cells of the top call. ■\blacksquare

Back to Hirschberg's algorithm