PrepStack · Markdown HTML

Divide, recurse, and combine

Divide and conquer · HTML

Formal shape

T(n)=aT(n/b)+C(n). A split defines subdomains, solve returns a minimal sufficient summary, combine constructs the parent summary, and base-sized domains are solved directly.

Recognition signals

False friends

SignalWhy it is different
Heavily overlapping subproblemsRepeated states call for memoization or DP; pure recursion repeats exponential work.
A combine step harder than the originalIf every level recomputes O(n²) work, splitting has not delivered leverage.
Recursion by itselfRecursion is control flow; divide-and-conquer also needs independent subproblems and a summary contract.

Core invariant

solve(lo,hi) returns a complete summary conforming to its domain contract; combine depends only on child summaries and accounts for every cross-domain contribution exactly once.

State, transition, and processing order

ItemDefinition
StateA current half-open domain [lo,hi), its returned summary, and optionally a reusable scratch buffer.
TransitionReturn directly at the base case; otherwise split, solve child summaries, then combine them.
Frontier / orderDomains awaiting solution or combination on the recursion stack, normally completed postorder.

Python skeleton

def divide_solve(items):
    def solve(lo, hi):
        if hi - lo <= 1:
            return items[lo:hi]
        mid = lo + (hi - lo) // 2
        left = solve(lo, mid)
        right = solve(mid, hi)
        merged, i, j = [], 0, 0
        while i < len(left) and j < len(right):
            if left[i] <= right[j]:
                merged.append(left[i]); i += 1
            else:
                merged.append(right[j]); j += 1
        return merged + left[i:] + right[j:]
    return solve(0, len(items))

Correctness sketch

  1. The base-sized domain is correct by direct construction.
  2. Assume inductively that every child call returns its complete contracted summary.
  3. The combine contract preserves internal answers and adds all cross-boundary information, proving the parent and ultimately the root.

Complexity

TimeSpaceParameters
Determined by T(n)=aT(n/b)+C(n); balanced binary split with linear combine is O(n log n)Typically O(n) scratch plus O(log n) stacka is child count, b the shrink factor, and C(n) combine cost.

Edge cases

Error patterns

PatternWhy it fails / fix
Inconsistent interval conventionsUse [lo,hi) and hi-lo<=1 consistently to avoid midpoint gaps or overlap.
Slicing at every levelCopies inflate memory and constants; pass bounds and reuse a buffer when performance matters.
No return-summary contractThe parent cannot combine a child result whose meaning was never specified.
Misusing the Master TheoremUneven sizes or irregular costs require a recursion-tree or amortized analysis.

Selection and exclusion rules

RelationTemplateBoundary
contrastExchange-argument greedy orderingDivide-and-conquer combines subanswers; exchange greedy replaces local order.
contrastInterval dynamic programmingUse divide-and-conquer for a fixed split; use interval DP when every split must compete.
structural basisSegment tree range aggregationReasoning about interval decomposition and combination
structural-analogyTree recursive aggregationA natural tree combines child summaries at each parent.

Original micro-example

PartDetail
ResultEach level performs O(7) merge work over about log 7 levels.
SetupSeven readings are split by position and sorted.
TraceRecursion sorts each half; combination compares only the two smallest unconsumed heads.

Recall prompts

My notes