Algorithm Search⌘K

Proofs: Two-pointer interval list intersection

These are the human proofs of Two-pointer interval list intersection, at full length.

The two-pointer scan returns every nonempty intersection in order full

This proof shows: correctness, termination.

We use the pseudocode of the page. The lists are A[1…m]A[1 \ldots m] and B[1…n]B[1 \ldots n]. Write A[p]=⟨ap,ap′⟩A[p] = \langle a_p, a'_p \rangle and B[q]=⟨bq,bq′⟩B[q] = \langle b_q, b'_q \rangle. For closed intervals the lists are sorted and disjoint when ap′<ap+1a'_p < a_{p+1} and bq′<bq+1b'_q < b_{q+1} for all pp and qq. For half-open intervals [ap,ap′)[a_p, a'_p) the condition is ap′≤ap+1a'_p \le a_{p+1} and bq′≤bq+1b'_q \le b_{q+1}. Line L5 tests lo≤hilo \le hi for closed intervals and lo<hilo < hi for half-open ones.

Claim. INTERSECT-LISTS stops, and it returns the list of all nonempty sets A[p]∩B[q]A[p] \cap B[q], each once, sorted from left to right.

Lemma 1 (line L5). In the step for the pair (i,j)(i, j), line L5 appends a piece if and only if A[i]∩B[j]≠∅A[i] \cap B[j] \ne \emptyset, and the piece it appends is A[i]∩B[j]A[i] \cap B[j].

Proof. For closed intervals, x∈[ai,ai′]∩[bj,bj′]x \in [a_i, a'_i] \cap [b_j, b'_j] if and only if max⁡(ai,bj)≤x≤min⁡(ai′,bj′)\max(a_i, b_j) \le x \le \min(a'_i, b'_j), that is lo≤x≤hilo \le x \le hi. So the intersection is [lo,hi][lo, hi], and it is nonempty if and only if lo≤hilo \le hi. For half-open intervals the same argument gives [lo,hi)[lo, hi), which is nonempty if and only if lo<hilo < hi. □\square

Lemma 2 (the discard). If ai′≤bj′a'_i \le b'_j, then A[i]∩B[q]=∅A[i] \cap B[q] = \emptyset for every q>jq > j. If bj′≤ai′b'_j \le a'_i, then A[p]∩B[j]=∅A[p] \cap B[j] = \emptyset for every p>ip > i.

Proof. Take q>jq > j. Since BB is sorted and disjoint, bq≥bj+1b_q \ge b_{j+1}. For closed intervals bj+1>bj′≥ai′b_{j+1} > b'_j \ge a'_i, so every point of B[q]B[q] is greater than ai′a'_i, and every point of A[i]A[i] is at most ai′a'_i. For half-open intervals bj+1≥bj′≥ai′b_{j+1} \ge b'_j \ge a'_i, so every point of B[q]B[q] is at least ai′a'_i, and every point of A[i]A[i] is less than ai′a'_i. In both cases the two sets are disjoint. The second statement is the same with the roles of AA and BB exchanged. □\square

Lemma 3 (order). If p<p′p < p', then every point of A[p]A[p] is less than every point of A[p′]A[p'], and the same holds for BB.

Proof. By the sorted and disjoint condition, ap′a'_p is at most ap+1≤ap′a_{p+1} \le a_{p'}, and for closed intervals ap′<ap+1a'_p < a_{p+1}. A point of A[p]A[p] is at most ap′a'_p (less than ap′a'_p for half-open intervals), and a point of A[p′]A[p'] is at least ap′a_{p'}. In each case the first is less than the second. □\square

Invariant. Let D(i,j)D(i, j) be the set of pairs (p,q)(p, q) with 1≤p≤m1 \le p \le m, 1≤q≤n1 \le q \le n, and p<ip < i or q<jq < j. Before each test of line L2:

(I) outout is the list of the nonempty sets A[p]∩B[q]A[p] \cap B[q] with (p,q)∈D(i,j)(p, q) \in D(i, j), each once, sorted from left to right.

Initialization. Line L1 sets i=j=1i = j = 1, so D(1,1)D(1, 1) is empty, and outout is empty.

Maintenance. Assume (I), with i≤mi \le m and j≤nj \le n, so the loop body runs. By Lemma 1, line L5 appends P=A[i]∩B[j]P = A[i] \cap B[j] if it is nonempty, and nothing else. The pair (i,j)(i, j) is not in D(i,j)D(i, j), so PP is not already in outout.

First, PP comes after every piece already in outout. Take a piece A[p]∩B[q]A[p] \cap B[q] in outout. If p<ip < i, the piece lies in A[p]A[p] and PP lies in A[i]A[i], so every point of the piece is less than every point of PP by Lemma 3. If q<jq < j, the same holds with BB. So outout stays sorted.

Next, consider line L6. If ai′<bj′a'_i < b'_j, it sets i←i+1i \leftarrow i + 1. Then D(i+1,j)=D(i,j)∪{(i,q):q≥j}D(i + 1, j) = D(i, j) \cup \{(i, q) : q \ge j\}. The pair (i,j)(i, j) is handled by line L5, and for q>jq > j the set A[i]∩B[q]A[i] \cap B[q] is empty by Lemma 2, since ai′≤bj′a'_i \le b'_j. So outout is the list for D(i+1,j)D(i + 1, j), and (I) holds.

Otherwise ai′≥bj′a'_i \ge b'_j, and line L7 sets j←j+1j \leftarrow j + 1. Then D(i,j+1)=D(i,j)∪{(p,j):p≥i}D(i, j + 1) = D(i, j) \cup \{(p, j) : p \ge i\}. The pair (i,j)(i, j) is handled by line L5, and for p>ip > i the set A[p]∩B[j]A[p] \cap B[j] is empty by the second part of Lemma 2, since bj′≤ai′b'_j \le a'_i. This case includes the tie ai′=bj′a'_i = b'_j. So (I) holds.

Termination. Each step increases i+ji + j by exactly 1, and the loop runs only while i+j≤m+ni + j \le m + n. So it stops after at most m+n−1m + n - 1 steps when m,n≥1m, n \ge 1, and at once when m=0m = 0 or n=0n = 0.

Conclusion. When the loop stops, i=m+1i = m + 1 or j=n+1j = n + 1. In the first case every p≤mp \le m satisfies p<ip < i; in the second every q≤nq \le n satisfies q<jq < j. Either way D(i,j)D(i, j) contains all mnmn pairs, and by (I) line L8 returns all nonempty sets A[p]∩B[q]A[p] \cap B[q], each once, sorted from left to right. These pieces are pairwise disjoint, because two different pairs differ in pp or in qq, and the intervals of each list are disjoint. ■\blacksquare

Back to Two-pointer interval list intersection