What is the two heaps pattern, and which problems does it solve?
The two heaps pattern keeps one max heap and one min heap and maintains an invariant that divides the data between them. The classic form for a running median keeps the lower half in the max heap and the upper half in the min heap, with the max heap holding either the same number of elements as the min heap or exactly one more.
That invariant gives you the median directly: the root of the max heap is the largest of the lower half, and if the two heaps are the same size the median is the average of that root and the root of the min heap. Every insertion and every removal touches only the heap roots, so both operations are logarithmic.
The same pattern solves other problems. A median of a sliding window uses it with an extra structure to expire old elements. A kth smallest or kth largest in a stream uses one heap with a size cap. Two heaps can also maintain the smallest and largest values of a collection at the same time, or split values by some threshold into a below group and an above group.
The trade-off to name is that two heaps hold the data twice over in terms of bookkeeping, so you pay roughly double the memory of a single heap plus the effort of keeping the invariant after every operation. The invariant itself is the hard part: every insertion and removal has to check which side the element belongs on and then rebalance by moving one element across. That rebalancing step is where most bugs in this pattern live.