Algorithm Search⌘K

Proofs: Palindrome partition dynamic programming

These are the human proofs of Palindrome partition dynamic programming, at full length.

Correctness of palindrome partition dynamic programming full

This proof shows: correctness.

We prove that PALINDROME-PARTITION-DP returns PL(s)\mathrm{PL}(s), the least number of nonempty palindromes whose concatenation is s=s[0..n−1]s = s[0..n-1], together with a partition of ss into that many palindromes. Indices are 0-based and s[j..i]s[j..i] includes both ends. We write PLi\mathrm{PL}_i for PL(s[0..i−1])\mathrm{PL}(s[0..i-1]), so PL0=0\mathrm{PL}_0 = 0.

Lemma 1 (the table). After the run of the outer loop for ii, for each 0≤j≤i0 \le j \le i, the entry pal[j][i]\mathrm{pal}[j][i] is true if and only if s[j..i]s[j..i] is a palindrome.

Proof. By induction on ii. The entry pal[j][i]\mathrm{pal}[j][i] is set only in the run for ii, by line L6, and only if the test of line L5 holds. If i−j≤1i - j \le 1, then s[j..i]s[j..i] is a palindrome if and only if s[j]=s[i]s[j] = s[i], which is the test. If i−j≥2i - j \ge 2, then s[j..i]s[j..i] is a palindrome if and only if s[j]=s[i]s[j] = s[i] and s[j+1..i−1]s[j+1..i-1] is a palindrome, because the mirror pairs of s[j..i]s[j..i] are (j,i)(j, i) and the mirror pairs of s[j+1..i−1]s[j+1..i-1]. The entry pal[j+1][i−1]\mathrm{pal}[j+1][i-1] is in column i−1i - 1, with j+1≤i−1j + 1 \le i - 1, so it is correct by the induction hypothesis, and no later run changes it. □\square

Lemma 2 (the recurrence). For 0≤i≤n−10 \le i \le n - 1,

PLi+1=min⁡{PLj+1:0≤j≤i, s[j..i] is a palindrome}.\mathrm{PL}_{i+1} = \min\{\mathrm{PL}_j + 1 : 0 \le j \le i,\ s[j..i] \text{ is a palindrome}\}.

Proof. The set is not empty, because s[i..i]s[i..i] is a palindrome. Let s[0..i]=p1⋯pks[0..i] = p_1 \cdots p_k be a partition into k=PLi+1k = \mathrm{PL}_{i+1} palindromes, and let pk=s[j..i]p_k = s[j..i]. Then p1⋯pk−1p_1 \cdots p_{k-1} is a partition of s[0..j−1]s[0..j-1] into palindromes, so k−1≥PLjk - 1 \ge \mathrm{PL}_j, and the right side is at most kk. Conversely, for each jj in the set, a partition of s[0..j−1]s[0..j-1] into PLj\mathrm{PL}_j palindromes followed by the piece s[j..i]s[j..i] is a partition of s[0..i]s[0..i] into PLj+1\mathrm{PL}_j + 1 palindromes, so PLi+1≤PLj+1\mathrm{PL}_{i+1} \le \mathrm{PL}_j + 1. □\square

Lemma 3 (the values). After the run of the outer loop for ii, best[i+1]=PLi+1\mathrm{best}[i+1] = \mathrm{PL}_{i+1}, and s[0..start[i+1]−1]s[0..\mathrm{start}[i+1]-1] followed by s[start[i+1]..i]s[\mathrm{start}[i+1]..i] is a split whose last piece is a palindrome and with best[start[i+1]]+1=best[i+1]\mathrm{best}[\mathrm{start}[i+1]] + 1 = \mathrm{best}[i+1].

Proof. By induction on ii, with best[0]=0=PL0\mathrm{best}[0] = 0 = \mathrm{PL}_0 from line L1. In the run for ii, line L3 sets best[i+1]\mathrm{best}[i+1] to ∞\infty, and the inner loop goes over j=0,…,ij = 0, \ldots, i. By Lemma 1, the test of line L5 holds exactly for the jj with s[j..i]s[j..i] a palindrome, and by the induction hypothesis best[j]=PLj\mathrm{best}[j] = \mathrm{PL}_j for these j≤ij \le i. Line L7 keeps the running minimum of best[j]+1\mathrm{best}[j] + 1 over them and the jj where it was reached. At the end of the run, by Lemma 2, best[i+1]=PLi+1\mathrm{best}[i+1] = \mathrm{PL}_{i+1}, and start[i+1]\mathrm{start}[i+1] is a jj with s[j..i]s[j..i] a palindrome and PLj+1=PLi+1\mathrm{PL}_j + 1 = \mathrm{PL}_{i+1}. Later runs do not change best[i+1]\mathrm{best}[i+1] or start[i+1]\mathrm{start}[i+1]. □\square

Lemma 4 (the rebuild). Lines L8 and L9 put best[n]\mathrm{best}[n] pieces into pieces\mathit{pieces}, each a palindrome, and their concatenation is ss.

Proof. We show the invariant: at each test of line L9, pieces\mathit{pieces} is a list of best[n]−best[i]\mathrm{best}[n] - \mathrm{best}[i] palindromes whose concatenation is s[i..n−1]s[i..n-1]. At the start i=ni = n and the list is empty. If i>0i > 0, let j=start[i]j = \mathrm{start}[i]. By Lemma 3, s[j..i−1]s[j..i-1] is a palindrome and best[j]=best[i]−1\mathrm{best}[j] = \mathrm{best}[i] - 1, so after line L9 the list holds best[n]−best[j]\mathrm{best}[n] - \mathrm{best}[j] palindromes whose concatenation is s[j..n−1]s[j..n-1], and the new value of ii is jj. Since j≤i−1j \le i - 1, the loop stops after at most nn steps, with i=0i = 0 and best[0]=0\mathrm{best}[0] = 0. □\square

Theorem. PALINDROME-PARTITION-DP returns PL(s)\mathrm{PL}(s) and a partition of ss into PL(s)\mathrm{PL}(s) palindromes.

Proof. For n=0n = 0 the outer loop does not run and the result is 00 with the empty partition, which is correct. For n≥1n \ge 1, Lemma 3 with i=n−1i = n - 1 gives best[n]=PLn=PL(s)\mathrm{best}[n] = \mathrm{PL}_n = \mathrm{PL}(s), and Lemma 4 shows that the returned pieces form a partition of ss into best[n]\mathrm{best}[n] palindromes. Both loops are bounded, so the algorithm stops. ■\blacksquare

Back to Palindrome partition dynamic programming