Understand
30-second explanation
Build the interview-ready mental model before comparing implementations.
You have a system x ≡ a₁ (mod m₁), x ≡ a₂ (mod m₂), …, x ≡ a_k (mod m_k) where the moduli are pairwise coprime. CRT says there's a unique solution x modulo M = m₁·m₂·…·m_k, and gives a construction. Let Mᵢ = M / mᵢ. Because mᵢ is coprime to every other modulus, Mᵢ is invertible mod mᵢ; let yᵢ = Mᵢ⁻¹ mod mᵢ (extended Euclid). Then x = (Σ aᵢ · Mᵢ · yᵢ) mod M. The term aᵢ·Mᵢ·yᵢ equals aᵢ mod mᵢ and 0 mod every other modulus, so the sum satisfies all congruences at once.
Interview contextWhat is testedWhere candidates slipHow to stand outExplore interview contextHide interview context
What's being tested
Whether you can state the coprimality precondition, construct the solution from orthogonal basis terms (each aᵢ·Mᵢ·yᵢ correct mod mᵢ and zero elsewhere), and produce the inverses with extended Euclid — plus handle overflow when M is large.
Where candidates slip
Assuming a solution always exists even when moduli aren't coprime, forgetting to reduce into [0, M), or letting aᵢ·Mᵢ·yᵢ overflow because mulmod / big ints weren't used.
How to stand out
Explain the orthogonality — why Mᵢ·yᵢ ≡ 1 (mod mᵢ) and ≡ 0 (mod mⱼ) — and present the iterative pairwise merge as the numerically stable way to combine many congruences, with the gcd consistency check for the non-coprime generalisation.
Choose
Compare the available approaches
Use constraints and trade-offs to select the route you can defend in an interview.
Interactive decision treeInteractiveChoose the right approachExplore the full treeCollapse the tree
How to read it:Each term aᵢ·Mᵢ·yᵢ equals aᵢ mod mᵢ and 0 mod every other modulus; summing them satisfies all congruences.
Learn & trace
Build each solution step by step
Move from the core idea to a visual trace, implementation, proof, and edge cases.
Approach 1 of 2
Brute-Force Search (Baseline)
1Hint 1Explore hintHide hint
By definition, x satisfies every congruence. What's the most direct way to find such an x without any number theory?
2Hint 2Explore hintHide hint
Try every candidate x from 0 up to M − 1 and check x mod mᵢ == aᵢ for all i. The first that passes is the unique answer.
3Hint 3Explore hintHide hint
That's O(M · k). M is the product of all moduli, so it explodes — for moduli like 1e9 each, M is astronomically large. What structure lets us construct x directly?
A · Core idea
The definition is directly testable: x is a solution iff x mod mᵢ == aᵢ for every i. Brute force tries each candidate x in [0, M) and returns the first that passes all k checks.
Why it is correct. CRT guarantees exactly one solution in [0, M), so a linear scan over that range is certain to find it. With pairwise-coprime moduli the scan never comes up empty.
Why it doesn't ship. M is the product of the moduli, so it grows multiplicatively in k. Even three moduli near 10⁹ push M past 10²⁷ — there is no scanning that. The brute force is O(M·k), exponential in the input's bit-length.
The structure we ignore. Scanning treats x as a black box. But the congruences are independent in a precise sense: because the moduli are coprime, you can build a number that controls each residue separately and add the pieces. Recognising that 'separate, then recombine' is possible is the leap to the constructive CRT.
B · Visual dry run
Interactive dry run
Select a frame to connect the decision with its visual state.
x ≡ 2 (mod 3), x ≡ 3 (mod 5), x ≡ 2 (mod 7)x=2
2 mod 3 = 2 ✓, 2 mod 5 = 2 ✗
fail23C · Code with teaching comments
Reference implementation previewpublic long crtBruteForce(long[] a, long[] m) { long M = 1; for (long mi : m) M *= mi; // assumes M fits in long for the demo for (long x = 0; x < M; x++) { boolean ok = true;Explore the full codeHide the full code
D · Why it works and complexityO(M · k) timeO(1) spaceOpen the invariant and proofExplore the proofHide the proof
Brute force is only a definition check — useful to verify a constructed answer on tiny inputs, never to compute it. The whole point of CRT is that you never need to search: the solution can be assembled directly from the residues.
ComplexityO(M · k) time, O(1) space — Scanning x from 0 to M − 1 and testing k congruences each is O(M·k). Since M is the product of the moduli, it grows multiplicatively and is hopeless beyond tiny inputs; space is O(1).
E · Edge cases and pitfalls3Running it when M is large — multiplicative blowup makes it infeasible.Explore edge casesHide edge cases
Pitfalls
- Running it when M is large — multiplicative blowup makes it infeasible.
- Assuming M fits in a 64-bit integer for the loop bound — it rarely does.
- Treating it as a real algorithm rather than a correctness check on tiny inputs.
Approach 2 of 2 · Optimal
Constructive CRT — Orthogonal Basis / Iterative Merge (Optimal)
1Hint 1Explore hintHide hint
Suppose you could build, for each i, a number that equals aᵢ when reduced mod mᵢ but equals 0 mod every other modulus. What happens when you add all k of them?
2Hint 2Explore hintHide hint
Let M = ∏ mⱼ and Mᵢ = M / mᵢ. Mᵢ is divisible by every mⱼ (j ≠ i), so it's 0 mod those. To make it ≡ 1 mod mᵢ, multiply by yᵢ = Mᵢ⁻¹ mod mᵢ (extended Euclid). Then aᵢ·Mᵢ·yᵢ is your basis term.
3Hint 3Explore hintHide hint
Sum the terms and reduce mod M. Equivalently, merge two congruences at a time: combine (a₁, m₁) and (a₂, m₂) into one congruence mod m₁·m₂, then fold in the next — this keeps the numbers smaller.
A · Core idea
Construct the solution directly instead of searching. Two equivalent framings; both rest on the same orthogonality idea.
The orthogonal-basis construction. Set M = m₁·m₂·…·m_k and, for each i, Mᵢ = M / mᵢ. The number Mᵢ is a product of every modulus except mᵢ, so Mᵢ ≡ 0 (mod mⱼ) for all j ≠ i. By itself Mᵢ is not ≡ 1 (mod mᵢ), but since mᵢ is coprime to every factor of Mᵢ, Mᵢ is invertible mod mᵢ. Let yᵢ = Mᵢ⁻¹ (mod mᵢ), computed with the extended Euclidean algorithm. Now the basis term eᵢ = Mᵢ·yᵢ satisfies eᵢ ≡ 1 (mod mᵢ) and eᵢ ≡ 0 (mod mⱼ) for j ≠ i — it is an 'indicator' for modulus i. Therefore x = Σ aᵢ·eᵢ (mod M) reduces, modulo any particular mⱼ, to just aⱼ·1 + (other terms)·0 = aⱼ — every congruence is satisfied at once.
Why coprimality is essential. Two things hinge on it. First, Mᵢ is invertible mod mᵢ only because mᵢ shares no factor with the other moduli; without that, yᵢ doesn't exist. Second, coprimality is what makes the solution unique mod M: if x and x' both solve the system then mᵢ | (x − x') for all i, and pairwise-coprime moduli give M | (x − x'). Drop coprimality and you either lose existence or lose uniqueness.
The iterative pairwise merge (numerically cleaner). Instead of forming the giant M up front, merge two congruences into one and repeat. Given x ≡ a₁ (mod m₁) and x ≡ a₂ (mod m₂), write x = a₁ + m₁·t. Substituting into the second congruence: a₁ + m₁·t ≡ a₂ (mod m₂), so t ≡ (a₂ − a₁)·(m₁⁻¹) (mod m₂). Then the merged congruence is x ≡ a₁ + m₁·t (mod m₁·m₂). Fold congruences in one at a time; the running modulus is the product so far, which keeps intermediates as small as possible and makes the gcd consistency check easy to insert for the non-coprime case (a solution exists only if (a₂ − a₁) is divisible by gcd(m₁, m₂)).
Why normalise. The summed/merged value can land outside [0, M) (especially with negative inverses), so finish with ((x % M) + M) % M to return the canonical representative.
Why overflow demands care. M, Mᵢ, and aᵢ·Mᵢ·yᵢ blow past 64 bits quickly. In Java, multiply with a mulmod (e.g. via Math.multiplyHigh / 128-bit logic or BigInteger) and reduce after each step; divide M / mᵢ exactly before multiplying back to limit growth. Python integers are unbounded, so the arithmetic is exact with no overflow, and the modulus is for keeping the final answer canonical.
B · Visual dry run
Interactive dry run
Select a frame to connect the decision with its visual state.
x ≡ 2 (mod 3), x ≡ 3 (mod 5), x ≡ 2 (mod 7)Array state
start
x=0, mod=1
23C · Code with teaching comments
D · Why it works and complexityO(k log M) timeO(1) beyond inputs spaceOpen the invariant and proofExplore the proofHide the proof
CRT is the 'partition of unity' for modular arithmetic: build indicator numbers that are 1 on their own modulus and 0 on the rest, then any target residues are reachable by a weighted sum. The pairwise merge is the same theorem expressed as a fold — preferable in code because it keeps intermediates small and slots in the gcd check needed when moduli aren't coprime.
ComplexityO(k log M) time, O(1) beyond inputs space — Either form does O(k) modular inverses (extended Euclid, O(log m) each) plus O(k) multiplications, so O(k log M). Space is O(1) beyond storing the inputs. The iterative merge keeps intermediate values bounded by the running product.
E · Edge cases and pitfalls9single congruence x ≡ a (mod m) — Merge runs once; returns a mod m.Explore edge casesHide edge cases
Edge cases handled
single congruence x ≡ a (mod m)Merge runs once; returns a mod m.all aᵢ = 0x = 0 satisfies every congruence; returns 0.moduli not coprime, consistentGeneralised merge succeeds only if (a₂−a₁) divisible by gcd; modulus becomes lcm, not product.moduli not coprime, inconsistentgcd check fails → report no solution.
Pitfalls
- Assuming a solution exists when moduli aren't coprime — add the gcd consistency check.
- Forgetting to normalise into [0, M) — negative inverses leak a negative answer.
- Letting M or aᵢ·Mᵢ·yᵢ overflow in Java — use BigInteger or mulmod, reduce per step.
- Computing M then Mᵢ = M / mᵢ with integer overflow before the division — prefer the iterative merge.
- Inverting Mᵢ mod mⱼ (wrong modulus) — the inverse must be taken mod mᵢ.
Practice
Try the solution yourself
Edit the optimal implementation, test another input, and observe the result.
Editable code previewimport java.math.BigInteger; import java.util.*; public BigInteger crt(long[] a, long[] m) { // Iterative pairwise merge; BigInteger avoids overflow in the product.Explore the playgroundClose the playground
Avoid mistakes
Recognize the interview traps
Understand why common attempts fail before reviewing the corrected implementation.
1Ignoring the coprimality precondition
Classic CRT needs pairwise-coprime moduli. With shared factors, Mᵢ may not be invertible mod mᵢ, and the system can be inconsistent. The generalised merge needs (a₂ − a₁) divisible by gcd(m₁, m₂).
Explore the code comparisonHide the code comparison
Ignoring the coprimality precondition
Classic CRT needs pairwise-coprime moduli. With shared factors, Mᵢ may not be invertible mod mᵢ, and the system can be inconsistent. The generalised merge needs (a₂ − a₁) divisible by gcd(m₁, m₂).
Don't write this
inv = pow(mod, -1, mi) # throws if gcd(mod, mi) != 1, or silently wrong assumptionsWrite this instead
g = math.gcd(mod, mi)
if (ai - x) % g != 0:
return None # inconsistent system
# ... generalised merge using lcm and inverse of (mod // g) ...2Not normalising the result
Basis terms or merge updates can produce a value outside [0, M) (negative inverses, large sums). Returning it raw gives a non-canonical or negative answer.
Explore the code comparisonHide the code comparison
Not normalising the result
Basis terms or merge updates can produce a value outside [0, M) (negative inverses, large sums). Returning it raw gives a non-canonical or negative answer.
Don't write this
return x; // may be negative or >= MWrite this instead
return x.mod(mod); // canonical representative in [0, M)3Overflow in the product and basis terms
M = ∏ mᵢ and aᵢ·Mᵢ·yᵢ blow past 64 bits fast. Plain long multiplication overflows to garbage; use BigInteger (Java) or big ints (Python), or a mulmod.
Explore the code comparisonHide the code comparison
Overflow in the product and basis terms
M = ∏ mᵢ and aᵢ·Mᵢ·yᵢ blow past 64 bits fast. Plain long multiplication overflows to garbage; use BigInteger (Java) or big ints (Python), or a mulmod.
Don't write this
long M = 1;
for (long mi : m) M *= mi; // overflows long for several moduli
long term = a[i] * (M / m[i]) * y[i]; // overflows againWrite this instead
BigInteger M = BigInteger.ONE;
for (long mi : m) M = M.multiply(BigInteger.valueOf(mi));
// terms via BigInteger.multiply, reduced mod MRevise
Carry the pattern into the interview
Pattern to remember
Build the solution as a sum of basis terms, each correct for one modulus and zero on the rest
Code pattern to memorize
M = product of all m_i
for each i: M_i = M / m_i
y_i = modInverse(M_i mod m_i, m_i) # extended Euclid
x = (sum of a_i * M_i * y_i) mod M
# pairwise iterative merge of (a1,m1),(a2,m2):
# x = a1 + m1 * ((a2 - a1) * inv(m1 mod m2, m2) mod m2)Rules to remember
- 1The moduli must be pairwise coprime for the classic CRT. If they aren't, the system may have no solution, or you need the generalised merge with a consistency check
(a₁ − a₂) divisible by gcd(m₁, m₂). - 2Each basis term
aᵢ·Mᵢ·yᵢis designed to be≡ aᵢ (mod mᵢ)and≡ 0 (mod mⱼ)forj ≠ i— that orthogonality is why the sum works. - 3
Mᵢ = M / mᵢis invertible modmᵢbecause it's a product of moduli all coprime tomᵢ; get the inverse from extended Euclid. - 4The product
Mand intermediate termsaᵢ·Mᵢ·yᵢoverflow fast — multiply with(__int128-style)longcare using mulmod, or use Python big ints. Divide-before-multiply where possible. - 5Normalise the answer into
[0, M)with((x % M) + M) % M; the construction can produce a value outside that range before reduction.
Use this pattern when
- Solve a **system of congruences** with pairwise-coprime moduli
- Reconstruct a big result from its residues modulo several small primes (CRT after computing mod p₁, p₂, …)
- Speed up big-integer arithmetic by working in independent modular channels, then recombining
- Counting / scheduling problems that reduce to 'x leaves remainder aᵢ when divided by mᵢ'
Choose another pattern when
- A single congruence → just reduce; CRT is for systems
- Moduli share factors and you only want the classic theorem → either no solution or you need the generalised CRT with a gcd check
- You need a modular inverse, not a system → extended Euclid alone
- The combined modulus M is required but overflows and you don't reduce per-channel → rethink representation
Interview takeaway
CRT turns a system of remainders into one congruence modulo the product. The construction is 'sum of orthogonal basis terms': each term hits its own modulus and vanishes on the others, so adding them satisfies everything simultaneously. The two pillars are pairwise-coprimality (guarantees uniqueness mod M and that each Mᵢ is invertible) and the modular inverse from extended Euclid. Iterating the two-congruence merge is the cleaner way to combine many at once and to keep numbers small.
Continue
Transfer the pattern to another problem
Use a direct variation or pattern sibling to prove the idea is reusable.
Transferable patternChinese Remainder Theorem — solve a system of congruences with coprime moduli. Recognise it whenever a quantity is known only by its remainders modulo several coprime numbers, or when you split a hard modular computation into independent prime-power channels and recombine. The orthogonal-basis sum and the iterative pairwise merge are two views of the same constructive proof.
Practice queueDirect variations and pattern siblings
Direct follow-ups
- Extended Euclidean AlgorithmSupplies the modular inverses Mᵢ⁻¹ that the construction needs.
- Modular ExponentiationOften paired with CRT to reconstruct a^k modulo a composite from its prime-power channels.
- GCD and LCMThe non-coprime generalisation merges with modulus lcm(m₁, m₂) and a gcd consistency check.
- nCr mod pCompute nCr modulo several primes, then CRT-combine to get it modulo their product.