Algorithm Search⌘K

Proofs: Two pointers with distinct counts

These are the human proofs of Two pointers with distinct counts, at full length.

Two pointers with distinct counts finds the longest window with at most k values full

This proof shows: correctness.

We use the pseudocode of the page on A[0..n−1]A[0..n-1] and k≥0k \ge 0. For 0≤i≤j≤n0 \le i \le j \le n let D(i,j)D(i, j) be the number of distinct values in A[i..j)A[i..j), with D(j,j)=0D(j, j) = 0. Call A[i..j)A[i..j) valid if D(i,j)≤kD(i, j) \le k. For 0≤j≤n0 \le j \le n let L(j)L(j) be the smallest i≤ji \le j such that A[i..j)A[i..j) is valid. It exists because A[j..j)A[j..j) is valid.

Lemma 1 (monotone). If i≤i′≤j′≤ji \le i' \le j' \le j then D(i′,j′)≤D(i,j)D(i', j') \le D(i, j). So a subarray of a valid subarray is valid, and L(j)≤L(j+1)L(j) \le L(j + 1) for 0≤j<n0 \le j < n.

Proof. The values of A[i′..j′)A[i'..j') are among those of A[i..j)A[i..j). If i<L(j)i < L(j) then A[i..j)A[i..j) is not valid, so neither is A[i..j+1)A[i..j+1), which contains it. Hence L(j+1)≥L(j)L(j + 1) \ge L(j). ■\blacksquare

Invariant. At the start of the step for jj (line L2), i=L(j)i = L(j), the table cntcnt maps each value of A[i..j)A[i..j) to its positive count and holds no other key, and d=D(i,j)d = D(i, j). After line L7 of the same step, the same holds with j+1j + 1 in place of jj.

Proof. For j=0j = 0, line L1 gives i=0=L(0)i = 0 = L(0), an empty table, and d=0d = 0.

Assume the invariant at the start of the step for jj. Lines L3 and L4 add one to the count of A[j]A[j], and add a key and one to dd exactly when A[j]A[j] is not in A[i..j)A[i..j). So the table and d=D(i,j+1)d = D(i, j + 1) are correct for the window A[i..j+1)A[i..j+1). Now i=L(j)≤L(j+1)i = L(j) \le L(j + 1) by Lemma 1.

Each run of lines L6 and L7 takes A[i]A[i] out of the window: it lowers its count, deletes the key and lowers dd when the count reaches zero, which is when A[i]A[i] is not in A[i+1..j+1)A[i+1..j+1). So the table and dd stay correct for the window A[i..j+1)A[i..j+1) with the new ii. The loop runs while d>kd > k, that is while the window is not valid. If i<L(j+1)i < L(j + 1) the window is not valid by the definition of LL, so the loop continues. At i=L(j+1)i = L(j + 1) the window is valid and the loop stops. Since the loop starts with i≤L(j+1)i \le L(j + 1), it stops with i=L(j+1)i = L(j + 1). ■\blacksquare

Theorem. DISTINCT-WINDOW returns best=max⁡{ j−i:0≤i≤j≤n, D(i,j)≤k }best = \max\{\, j - i : 0 \le i \le j \le n,\ D(i, j) \le k \,\} and a start startstart with D(start,start+best)≤kD(start, start + best) \le k.

Proof. For a fixed end j′=j+1j' = j + 1, the valid subarrays A[i..j′)A[i..j') are those with i≥L(j′)i \ge L(j'), by Lemma 1, and the longest of them has length j′−L(j′)j' - L(j'). By the invariant, line L8 tests exactly this length, j+1−ij + 1 - i, for every j′=1,…,nj' = 1, \dots, n. The end j′=0j' = 0 gives only the empty subarray, with length 00, which is the starting value of bestbest in line L1. So after the loop, bestbest is the maximum over all ends, and startstart is the start of a window of that length that was valid when it was recorded. Each step moves jj once, and ii moves at most nn times in total because i≤j+1i \le j + 1, so the algorithm stops. ■\blacksquare

Back to Two pointers with distinct counts