A nightly job must count records matching none of k taint filters - why must the correction terms alternate in sign?
answer
- over-correct, then correct the correction
- start from the total, remove each filter
- pairs come back, triples go out again
- a j-filter term carries sign (-1)^j
- (1-1)^m = 0 for every tainted record
basics
~20 sSubtracting each filter's matches over-corrects records caught by several filters, so pairwise overlaps are added back, triples removed again, and so on. The alternating signs make every record matching at least one filter cancel to exactly zero.
solid answer
~50 sStart from the total `N` and subtract each filter's match count. A record caught by two filters has now been removed twice, so you add every pairwise intersection back; a record caught by three has been removed three times and restored three times, so it is still counted and the triples must come out again. The general shape is `N - sum|Ai| + sum|Ai and Aj| - sum|Ai and Aj and Ak| ...`, where a term built from `j` filters carries the sign `(-1)^j`. The alternation is not a convention: a record caught by exactly `m >= 1` filters contributes `sum_j (-1)^j C(m,j)`, which is the binomial expansion of `(1-1)^m` and therefore zero, while a clean record is counted once by the leading `N`. Every term is needed - stopping early leaves a bound rather than the count.
go deeper
Recall the shape: add the parts, subtract the shared pieces, add the shared-by-three pieces back. Knowing that plain addition double counts anything caught twice is already the main idea.
Explain the mechanics: what the sign of a j-filter term is, why the correction has to keep alternating, and that a record caught by m filters contributes a signed binomial row summing to zero.
Show the operational judgment: where the intersection counts actually come from, what a truncated sum buys when the deep terms are unmeasurable, and which direction the resulting bound points.
Frame the trade-off: whether the reporting layer should expose arbitrary intersection counts at all, or whether the conditions should be restructured into disjoint segments so no signed sum is needed.
## The counting problem A nightly deduplication job ingests several overlapping feeds and runs `k` **taint filters** over the merged stream - a filter marks a record as suspect for some reason (a blocked source, a malformed key, a stale timestamp). What the pipeline must report is the number of **clean** records: those that trip *none* of the filters. The only figures available from the reporting layer are match counts - how many records each filter caught, and how many were caught by a given combination of filters. The naive move is to add up the per-filter counts, subtract that from the total, and ship it. That is wrong whenever two filters can catch the same record, which is exactly the situation the job exists for. ## Why one subtraction over-corrects Write `N` for the total number of records and `A1 ... Ak` for the sets of records each filter catches. Follow a single record through the arithmetic: - a record caught by **no** filter is counted once in `N` and never touched again - correct; - a record caught by **one** filter is counted once, subtracted once - correct, it reaches zero; - a record caught by **two** filters is counted once and subtracted **twice** - it now contributes `-1`, so the count of clean records comes out too low; - a record caught by **three** filters is subtracted three times, contributing `-2`. So the first correction does not merely fail to be exact; it drives the answer in a direction that grows with how much the filters overlap. Adding every pairwise intersection back fixes the two-filter records, but a three-filter record sits in three different pairwise intersections and is now restored three times, landing back at `+1`. That is what forces the next subtraction, and the pattern does not stop until the intersections run out. ## The general statement The **inclusion-exclusion principle** states the clean count directly: `clean = N - sum |Ai| + sum |Ai and Aj| - sum |Ai and Aj and Ak| + ... + (-1)^k |A1 and ... and Ak|` A term built from an intersection of `j` filters carries the sign `(-1)^j`. There is one term for every subset of the `k` filters, including the empty subset whose intersection is the whole population and which supplies the leading `N`. That is `2^k` terms in total. The union form - the count of records caught by **at least one** filter - is the same identity rearranged, with `2^k - 1` non-empty terms and the signs starting negative. ## Why the alternation cancels exactly Take a record caught by exactly `m` filters and ask how many terms it appears in. It appears in every term built from a subset of *those* `m` filters, and there are `C(m,j)` such subsets of size `j`. Its net contribution is therefore the signed binomial row for `m`: | filters matched (m) | contributions by term size | net | |---|---|---| | 0 | +1 | 1 | | 1 | +1, -1 | 0 | | 2 | +1, -2, +1 | 0 | | 3 | +1, -3, +3, -1 | 0 | | m | sum of (-1)^j C(m,j) | (1-1)^m = 0 | The last row is the whole argument: the signed row sum is the binomial expansion of `(1 - 1)^m`, which is `0` for every `m >= 1` and `1` for `m = 0`. Every tainted record cancels itself out no matter how many filters caught it, and every clean record survives with weight one. Nothing about the filters is assumed - not independence, not disjointness, not similar sizes. It is an identity over finite sets, so it holds for whatever the data happens to look like. ## Stopping early on purpose Because the terms alternate, a **truncated** sum is not noise - it brackets the answer, and the direction depends on where you stopped. Summing the per-filter counts alone over-states the union (every multiply-caught record is counted more than once), so it gives an upper bound on the union and hence a lower bound on the clean count. Subtract the pairwise overlaps and you undershoot the union, which flips both bounds. Truncation is a legitimate engineering move when the deep intersections are expensive to measure, but it must be reported as a bound, never as the count. ## Where engineers get this wrong 1. **Stopping after the single subtraction**, which is only correct when no record can be caught twice - the case where the formula was not needed. 2. **Adding pairs back and stopping there**, which leaves triple-caught records mis-weighted and is the most common half-remembered version. 3. **Reaching for independence**, multiplying rates as if the filters were unrelated. Overlapping feeds correlate heavily, and the identity never needs that assumption anyway. 4. **Forgetting the empty term.** The leading `N` is a term of the sum, and dropping it turns the clean count into the negated union.
- If the deepest intersections are too expensive to measure, what does a truncated sum still give you?A bound with a known direction. Summing the per-filter counts alone over-states the union, so it is an upper bound on the union and therefore a lower bound on the clean count. Subtracting the pairwise overlaps under-states the union and flips both bounds. Each extra group of terms tightens the bracket, so you can report an interval and say where you stopped.
- Does the identity require the filters to be independent, or the sets to be similar in size?Neither. It is a counting identity over finite sets, proved by showing each element's signed contributions cancel, so it holds for arbitrarily correlated filters and wildly uneven sizes. Independence is a probabilistic assumption that would let you multiply rates instead - a different and usually false claim about overlapping feeds.
- How many terms does the exact clean count need for k filters?`2^k`, one for every subset of the filters, including the empty subset that contributes the total population size. The union form has `2^k - 1`. Each term is a real measurement - the size of one intersection - so the cost is in the measurements, not the arithmetic.
saying these in an interview costs you the question
- Subtracting every filter's count once and stopping there
- Adding the pairs back but never removing the triples
- Calling the alternating signs an arbitrary convention
- Assuming the filters must be independent to combine
- Treating a truncated sum as the exact count rather than a bound
- Dropping the leading total and returning the union instead