Algorithm Search⌘K

Proofs: Two-pointer pair search

These are the human proofs of Two-pointer pair search, at full length.

Two-pointer pair search finds a pair with sum t if and only if one exists full

This proof shows: correctness, termination.

We use the pseudocode of the page. The array A[0…n−1]A[0 \ldots n-1] is sorted, A[0]≤⋯≤A[n−1]A[0] \le \cdots \le A[n-1]. A solution is a pair of indices (i,j)(i, j) with 0≤i<j≤n−10 \le i < j \le n-1 and A[i]+A[j]=tA[i] + A[j] = t. Write Sol(a,b)\mathrm{Sol}(a, b) for the set of solutions (i,j)(i, j) with a≤i<j≤ba \le i < j \le b.

Claim. PAIR-SEARCH(A,t)(A, t) stops after at most max⁡(n−1,0)\max(n-1, 0) iterations of the loop of line L2. It returns a solution if a solution exists, and NIL otherwise.

Proof. We use this invariant, checked each time the test of line L2 is about to run:

(P) 0≤lo0 \le lo, hi≤n−1hi \le n - 1, lo≤hi+1lo \le hi + 1, and if Sol(0,n−1)≠∅\mathrm{Sol}(0, n-1) \ne \emptyset then Sol(lo,hi)≠∅\mathrm{Sol}(lo, hi) \ne \emptyset.

Initialization. Line L1 sets lo=0lo = 0 and hi=n−1hi = n - 1. Then lo≤hi+1lo \le hi + 1 because n≥0n \ge 0, and Sol(lo,hi)=Sol(0,n−1)\mathrm{Sol}(lo, hi) = \mathrm{Sol}(0, n-1), so the last part holds.

Maintenance. Assume (P) and lo<hilo < hi. Line L3 sets s=A[lo]+A[hi]s = A[lo] + A[hi]; both indices are in [0,n−1][0, n-1] by (P). If s=ts = t, line L4 returns (lo,hi)(lo, hi), which is a solution because lo<hilo < hi. Otherwise there are two cases.

  • Case s<ts < t (line L5). Take any (lo,j)(lo, j) with lo<j≤hilo < j \le hi. Because AA is sorted and j≤hij \le hi, A[j]≤A[hi]A[j] \le A[hi], so A[lo]+A[j]≤A[lo]+A[hi]=s<tA[lo] + A[j] \le A[lo] + A[hi] = s < t. So no solution in Sol(lo,hi)\mathrm{Sol}(lo, hi) has first index lolo, and Sol(lo,hi)=Sol(lo+1,hi)\mathrm{Sol}(lo, hi) = \mathrm{Sol}(lo + 1, hi). Line L5 sets lolo to lo+1lo + 1, so the last part of (P) still holds. The bounds hold because the new lolo is at most hihi.
  • Case s>ts > t (line L6). Take any (i,hi)(i, hi) with lo≤i<hilo \le i < hi. Because i≥loi \ge lo, A[i]≥A[lo]A[i] \ge A[lo], so A[i]+A[hi]≥A[lo]+A[hi]=s>tA[i] + A[hi] \ge A[lo] + A[hi] = s > t. So no solution in Sol(lo,hi)\mathrm{Sol}(lo, hi) has second index hihi, and Sol(lo,hi)=Sol(lo,hi−1)\mathrm{Sol}(lo, hi) = \mathrm{Sol}(lo, hi - 1). Line L6 sets hihi to hi−1hi - 1, and (P) holds as before; the new hihi is at least lo≥0lo \ge 0.

In both cases no solution of the old range is lost: this is the statement that a pointer move never skips an answer.

Termination. Let d=hi−lod = hi - lo. Each iteration that does not return runs exactly one of lines L5 and L6, and each of them decreases dd by exactly 1. At the start d=n−1d = n - 1, and the loop runs only while d≥1d \ge 1. So there are at most n−1n - 1 iterations when n≥1n \ge 1, and none when n=0n = 0.

Result. If line L4 returns, the result is a solution, as shown. Otherwise the loop stops with lo≥hilo \ge hi, so lo=hilo = hi or lo=hi+1lo = hi + 1 by (P). Then no pair (i,j)(i, j) with lo≤i<j≤hilo \le i < j \le hi exists, and Sol(lo,hi)=∅\mathrm{Sol}(lo, hi) = \emptyset. By the contrapositive of the last part of (P), Sol(0,n−1)=∅\mathrm{Sol}(0, n-1) = \emptyset, so NIL is the right answer. ■\blacksquare

Exact count on a no-answer input. If no solution exists, line L4 never returns, so each iteration decreases dd by 1 from n−1n - 1 to 0, and the loop runs exactly n−1n - 1 times for n≥1n \ge 1.

Remark on the order of solutions. The proof shows only that some solution stays in the range. A specific solution can leave the range: on A=[1,2,3,4]A = [1, 2, 3, 4] with t=5t = 5, the algorithm returns (0,3)(0, 3) and never looks at the solution (1,2)(1, 2). To list all solutions, use the variant of the page that skips the blocks of equal items after a match.

Back to Two-pointer pair search