Multi-threaded
Left and right subtrees are completely independent — spawn a thread per subtree, run in parallel, join before combining. The producer-consumer pattern handles lazy iteration with bounded memory.
Sequential DFS visits left then right — but they share zero data. Run them on separate threads: same O(n) work, half the wall-clock time.
Submit ALL futures first, then collect results — never call .result() before submitting the next task
Shared flag: use
mismatch=[False] list wrapper — mutable in nested scopePython Threading Primitives
Four primitives cover 95% of multi-threaded interview problems.
Locklock = threading.Lock()
with lock:
shared_state = TrueShared mutable state — any variable multiple threads write to.
Semaphoresem = threading.Semaphore(n)
with sem:
pass # ≤ n threads hereRate-limiting — bounded buffer, max concurrent workers.
Evente = threading.Event() e.set() # signal on e.wait() # block until set
Thread A waits for Thread B's signal. Producer notifies consumer.
Barrierb = threading.Barrier(2)
b.wait() # blocks until
# 2 threads arriveRendezvous — both threads complete Phase 1 before Phase 2 starts.
The 3-Step Framework
Identify independence → submit all → collect results → protect shared writes.
Left and right subtrees share no nodes — always independent. Same Tree: left check AND right check. Invert Tree: invert left AND invert right. Any divide-and-conquer with independent halves is a candidate.
# Ask: does left need any result from right (or vice versa)? # Binary tree left/right: always NO # → spawn Thread-L and Thread-R
Future.result() blocks. If you call it before submitting the second task, the second task doesn't start until the first finishes — you've serialised. Always submit all, then collect all.
# CORRECT — both submitted before either blocks f1 = ex.submit(fn, left) f2 = ex.submit(fn, right) r1 = f1.result() # both already running r2 = f2.result()
Writing to a plain variable in a nested function creates a local. Use a list wrapper [False] — mutating an existing object works across nested scopes. For counters or complex state, use a Lock explicitly.
mismatch = [False] # list wrapper
def check(a, b):
mismatch[0] = True # mutates list — outer sees it
# NOT: mismatch = True (creates new local!)Pattern Recognition
'parallel subtrees', 'concurrent traversal', 'BST iterator' → multi-threaded.