Algorithm Search⌘K

Proofs: Naive string matching

These are the human proofs of Naive string matching, at full length.

Naive string matching outputs exactly the valid shifts full

This proof shows: correctness, termination.

Claim. For a text T[0…n−1]T[0 \ldots n-1] and a pattern P[0…m−1]P[0 \ldots m-1] with n,m≥0n, m \ge 0, NAIVE-STRING-MATCHING(T,P)(T, P) stops, and it outputs exactly the shifts ss with 0≤s≤n−m0 \le s \le n - m and T[s…s+m−1]=PT[s \ldots s+m-1] = P, each one time, in increasing order.

Setup. Fix one iteration of line L2, with shift ss, 0≤s≤n−m0 \le s \le n - m. So s+m≤ns + m \le n, and each index s+js + j with 0≤j<m0 \le j < m is a valid index of TT.

Lemma (inner loop). Each time line L4 tests its condition, the invariant

(I) 0≤j≤m0 \le j \le m and T[s+i]=P[i]T[s + i] = P[i] for each 0≤i<j0 \le i < j

is true.

Proof. 1. Initialization. Line L3 sets j=0j = 0. Then 0≤j≤m0 \le j \le m because m≥0m \ge 0, and the second part is about no index, so it is true.

  1. Maintenance. Assume (I) and that the test of line L4 is true. Then j<mj < m and T[s+j]=P[j]T[s + j] = P[j]. Line L5 sets j′=j+1≤mj' = j + 1 \le m. The equality for i=ji = j holds by the test, and the equalities for i<ji < j hold by (I). So (I) holds for j′j'.

  2. Termination. Each pass of the loop increases jj by exactly 1, and (I) gives j≤mj \le m. So the loop makes at most mm passes and stops. □\square

Lemma (one shift). Line L6 outputs ss if and only if T[s…s+m−1]=PT[s \ldots s+m-1] = P.

Proof. When the loop of line L4 stops, (I) holds and the test is false, so j=mj = m or T[s+j]≠P[j]T[s + j] \ne P[j] with j<mj < m.

  • If j=mj = m, then (I) gives T[s+i]=P[i]T[s + i] = P[i] for each i<mi < m, so ss is a valid shift, and line L6 outputs it.
  • If j<mj < m, then T[s+j]≠P[j]T[s + j] \ne P[j], so ss is not a valid shift, and line L6 outputs nothing.

The test j<mj < m is evaluated first, so the loop never reads P[m]P[m] or T[s+m]T[s + m]. □\square

Theorem. The claim holds.

Proof. If m>nm > n, then n−m<0n - m < 0, line L2 makes no iteration, and the output is empty. This is correct, because no ss satisfies 0≤s≤n−m0 \le s \le n - m. Otherwise, line L2 runs the body for s=0,1,…,n−ms = 0, 1, \ldots, n - m, each value one time and in increasing order, and each body stops by the first lemma. By the second lemma, the body for ss outputs ss exactly when ss is a valid shift. So the output is the list of valid shifts in increasing order, and the algorithm stops after n−m+1n - m + 1 iterations of line L2. If m=0m = 0, the loop of line L4 stops at once with j=0=mj = 0 = m, so each ss from 00 to nn is output, as the definition requires. ■\blacksquare

Back to Naive string matching