Algorithm Search⌘K

Proofs: Shiloach's least rotation algorithm

These are the human proofs of Shiloach's least rotation algorithm, at full length.

LEAST-ROTATION returns the smallest start of the least rotation full

This proof shows: correctness.

We use the pseudocode of the page. The word is s=s[0..n−1]s = s[0..n-1] with n≥1n \ge 1 over a totally ordered alphabet, all indices of ss are taken modulo nn, and rotj=s[j..n−1] s[0..j−1]\mathrm{rot}_j = s[j..n-1]\,s[0..j-1] for 0≤j≤n−10 \le j \le n - 1; for any integer jj we write rotj\mathrm{rot}_j for rotj mod n\mathrm{rot}_{j \bmod n}, so rotj[t]=s[j+t]\mathrm{rot}_j[t] = s[j + t]. Let R=min⁡jrotjR = \min_j \mathrm{rot}_j in lexicographic order. A start j∈{0,…,n−1}j \in \{0, \ldots, n-1\} is least if rotj=R\mathrm{rot}_j = R and a loser otherwise. Let m∗m^* be the smallest least start.

Lemma 1 (elimination). Let xx and yy be integers and 0≤k<n0 \le k < n with s[x+t]=s[y+t]s[x + t] = s[y + t] for 0≤t<k0 \le t < k and s[x+k]<s[y+k]s[x + k] < s[y + k]. Then for each 0≤t≤k0 \le t \le k, rotx+t<roty+t\mathrm{rot}_{x+t} < \mathrm{rot}_{y+t}, so (y+t) mod n(y + t) \bmod n is a loser.

Proof. The words rotx+t\mathrm{rot}_{x+t} and roty+t\mathrm{rot}_{y+t} have the same length nn. Their letters at positions 0,…,k−t−10, \ldots, k - t - 1 are s[x+t+r]s[x + t + r] and s[y+t+r]s[y + t + r] with t+r<kt + r < k, which are equal; at position k−t≤n−1k - t \le n - 1 they are s[x+k]<s[y+k]s[x + k] < s[y + k]. So the first is smaller. □\square

Lemma 2 (period). If rotg=roth\mathrm{rot}_g = \mathrm{rot}_h with 0≤g<h≤n−10 \le g < h \le n - 1, then rotj=rotj+(h−g)\mathrm{rot}_{j} = \mathrm{rot}_{j + (h - g)} for every integer jj.

Proof. s[g+t]=s[h+t]s[g + t] = s[h + t] for all 0≤t<n0 \le t < n, hence for all integers tt since indices are taken modulo nn. Put t=j−gt = j - g. □\square

Invariant. Before each test of line L2:

(I) 0≤g<h0 \le g < h, g≤n−1g \le n - 1, and every jj with 0≤j<min⁡(h,n)0 \le j < \min(h, n) and j≠gj \ne g is a loser.

In particular, by (I), m∗=gm^* = g or m∗≥hm^* \ge h.

Initialization. Line L1 sets g=0g = 0 and h=1h = 1; the only j<1j < 1 is gg.

Maintenance. Assume (I) and h<nh < n. Lines L3 to L5 end with the largest k≤nk \le n such that s[g+t]=s[h+t]s[g + t] = s[h + t] for 0≤t<k0 \le t < k. If k=nk = n, line L6 returns; that case is treated below. Otherwise k<nk < n and s[g+k]≠s[h+k]s[g + k] \ne s[h + k].

  • Line L8. Here s[g+k]<s[h+k]s[g + k] < s[h + k]. By Lemma 1 with x=gx = g, y=hy = h, the starts h,h+1,…,h+kh, h + 1, \ldots, h + k that are below nn are losers. With the old losers, every j<min⁡(h+k+1,n)j < \min(h + k + 1, n) other than gg is a loser, and g<h<h+k+1g < h < h + k + 1. So (I) holds with the new h=h+k+1h = h + k + 1.
  • Lines L10 and L11. Here s[h+k]<s[g+k]s[h + k] < s[g + k]. By Lemma 1 with x=hx = h, y=gy = g, the starts g,…,g+kg, \ldots, g + k below nn are losers. Let M=max⁡(h,g+k+1)M = \max(h, g + k + 1). Every j<Mj < M is a loser: if j<hj < h and j≠gj \ne g this is (I); j=gj = g was just shown; if h≤j<g+k+1h \le j < g + k + 1 then j=g+tj = g + t with 1≤t≤k1 \le t \le k. Since m∗m^* is not a loser, m∗≥Mm^* \ge M, so M≤n−1M \le n - 1. Line L10 sets g=Mg = M and line L11 sets h=M+1h = M + 1; then g≤n−1g \le n - 1, g<hg < h, and the only j<hj < h that may not be a loser is gg. So (I) holds.

Termination of the loop. If the loop ends because h≥nh \ge n, then by (I) every start other than gg is a loser, and m∗m^* exists, so m∗=gm^* = g and line L12 returns it.

The return at line L6. Here rotg=roth\mathrm{rot}_g = \mathrm{rot}_h with g<h≤n−1g < h \le n - 1; let d=h−gd = h - g. By (I), m∗=gm^* = g or m∗≥hm^* \ge h. Suppose m∗≥hm^* \ge h. The numbers m∗−d,m∗−2d,…m^* - d, m^* - 2d, \ldots decrease by dd, so exactly one of them, say j=m∗−qdj = m^* - qd with q≥1q \ge 1, lies in the interval [g,h)[g, h), which has length dd. By Lemma 2 applied qq times, rotj=rotm∗=R\mathrm{rot}_j = \mathrm{rot}_{m^*} = R, so jj is a least start with j<m∗j < m^*, contradicting the choice of m∗m^*. Hence m∗=gm^* = g and line L6 returns it.

The loop stops. Each pass of the loop of line L2 that does not return increases g+hg + h by at least k+1≥1k + 1 \ge 1: line L8 adds k+1k + 1, and lines L10 and L11 replace g+hg + h by 2M+1≥(g+k+1)+h+12M + 1 \ge (g + k + 1) + h + 1. While the loop runs, g+h≤2n−2g + h \le 2n - 2, so the number of passes is finite, and the inner loop of line L4 makes at most nn steps per pass.

Claim. LEAST-ROTATION returns m∗m^*, the smallest index at which the least rotation of ss starts. This follows from the two exits above. ■\blacksquare

Comparison count. A pass that stops at a difference after kk equal letters performs k+1k + 1 three-way letter comparisons and increases g+hg + h by at least k+1k + 1. Initially g+h=1g + h = 1. After the last such pass, g≤n−1g \le n - 1 and h≤(n−1)+(n−1)+1=2n−1h \le (n - 1) + (n - 1) + 1 = 2n - 1, so these passes perform at most 3n−33n - 3 comparisons in total. A pass that returns at line L6 performs nn comparisons and starts with g+h≤2n−3g + h \le 2n - 3, so the passes before it performed at most 2n−42n - 4 comparisons. In both cases the total is at most 3n−3<3n3n - 3 < 3n. Each comparison costs O(1)O(1) together with the index updates, so the running time is Θ(n)\Theta(n) and the extra space is Θ(1)\Theta(1). ∎

Back to Shiloach's least rotation algorithm