Under constant-cost lookup and integer addition, Memoized Fibonacci evaluation has time complexity in Big O notation, retaining values. A hash table needs its own lookup-cost assumptions; an array indexed by avoids hash collisions in this example. Memoization removes repeated bodies, but also pays for keys, lookups and retained answers. A workload without reuse can pay those costs without saving evaluations.
The call stack remains. Left-first recursion descends through arguments before returning, giving simultaneously active frames for . Therefore the auxiliary space complexity includes frames as well as table entries in the constant-size-value model. An iterative bottom-up dynamic programming calculation removes these recursive frames; retaining only the two previous Fibonacci numbers suffices when only the final value is wanted, but discards the table useful for later requests.
Exact Fibonacci numbers do not remain constant-size values. For , the recurrence relation gives , so the representation of as a binary number has order bits. With ordinary addition costing order bit operations on such operands, the additions cost order bit operations in total. Retaining all values also requires order bits of value storage, before keys and frame overhead. The linear bound counts additions under its stated cost model; it is not a linear bound on exact integer arithmetic in bits.[ref]
Merge algorithm Created 2026-10-13 Updated 2026-10-18
The merge algorithm combines two finite sorted sequences under the same total order, retaining every entry exactly once. Keep a position at the first unconsumed entry, or "head", of each input. While both heads exist, compare their keys, append the smaller head to the output, and advance only that head's position. On equality take the left head. Once either sequence is exhausted, append the other remainder without further key comparisons. Empty inputs therefore require no head comparisons. The MIT notes illustrate this two-head combination step.[ref]
For example, the merge algorithm applied to and returns :
Figure 1.
Five head comparisons in the merge algorithm
. Orange heads are chosen and arrows lead to the next output entry. The compared head pairs are (1,2), (4,2), (4,3), (4,8) and (7,8). The left sequence then runs out; append (8,9) without further key comparisons. Details.
The head pairs , , , and select respectively. After the fifth comparison the left sequence is empty, so is appended. Seven entries are written, but only five head comparisons occur: tests for exhaustion and appending the remainder are separate operations. This distinction makes the example's count smaller than the bound .
For nonempty inputs of lengths , each head comparison consumes exactly one entry. After such removals at most one entry remains, so both heads cannot still exist. Hence the merge algorithm uses at most head comparisons. The bound can be attained: and require six head comparisons before the left sequence is exhausted. With constant-cost comparisons, access and copying, writing all entries gives time complexity in Big O notation. Writing a separate output array needs entry slots; the two positions require only constant additional storage.
The merge algorithm is useful whenever two already ordered collections must become one: it reads each input only forwards. This works with arrays and linked lists, without needing access to arbitrary middle positions. Choosing left on ties preserves each input's internal order and places equal left entries before equal right entries, which is the combination rule needed for stable sorting in merge sort.
The loop invariant behind algorithm correctness is that the emitted prefix is sorted, contains exactly the consumed entries, and every emitted key is at most every unconsumed key. Each sorted sequence has its smallest remaining key at its head, so the smaller of the two heads is safe to append. The invariant survives each removal; when one sequence ends, the other sorted remainder is safe to append in full. Each comparison removes an entry, so termination follows from the finite input lengths.
// Target: computer-science.bigb
Merge sort Created 2026-10-13 Updated 2026-10-18
Merge sort is a divide-and-conquer algorithm that sorts a finite array by splitting it into contiguous halves, sorting each half using recursion, and combining the two sorted arrays with the merge algorithm. An empty or one-entry array is returned immediately. For length , put the first entries on the left and the remaining on the right; the brackets are the floor function and ceiling function. Always choose the left head on equal keys to obtain stable sorting. This is the split, sort, combine structure taught in the MIT lecture notes.[ref]
Take the concrete input array
The tags identify the entries originally at indices and , counting from zero. Both keys are ; the tags are never compared. Reading downward in the figure follows the splits, then the returned sorted arrays. Arrows show dependencies; the level layout groups independent calls rather than giving their chronological execution order.
Figure 1.
Merge sort splits into base cases and returns sorted arrays
. The tagged keys 2a and 2b retain their original order through stable sorting. The merge algorithm makes 4, 6 and 7 head comparisons on the three returning levels, for 17 in total. Details.
The first two halves are and . Their pairs split into one-entry base cases. Applying the merge algorithm gives the following fully worked return levels; each number in the last column counts only comparisons between two available heads.
Returning levelResulting sorted arraysHead comparisons
Pairs, , ,
Halves,
Whole array
In the left-half merge algorithm, the head pairs are , and ; it takes , then appends . In the final merge algorithm, the head pairs are , , , , , and . It takes , then appends . Thus this precise version makes head comparisons and, ignoring identity tags, returns .
The elegance of merge sort is that it creates exactly the structure its next step needs: two smaller sorted arrays make the larger ordering inexpensive. Once the whole array is sorted, equal keys are adjacent and binary search can serve repeated queries. Stable sorting also retains information that the keys alone do not express. If the left-half merge algorithm instead takes the right head on the tie, it returns ; the keys are sorted but stable sorting has failed.
For time complexity, assume each key comparison, entry access and entry copy has constant cost. The merge algorithm processes entries in time. In Big O notation, the resulting recurrence relation is
For , the balanced levels contain entries each and there are returning levels. Each costs , so the worst-case time complexity is . For arbitrary , there are at most returning levels, each processing at most entries, giving the same bound. The worst-case number of head comparisons is also . Here is the base-two logarithm. The MIT notes give this level-by-level analysis for merge sort.[ref]
The conventional array implementation uses a reusable buffer of entries for the merge algorithm, together with pending calls for recursion. Its auxiliary space complexity is therefore , beyond the original array. This bound describes that implementation. A linked list permits a merge algorithm that reconnects existing nodes; its storage accounting differs from copying array entries into a buffer.
For a short algorithm correctness outline, the empty and one-entry base cases are sorted. Assuming recursion correctly sorts both shorter halves, the merge algorithm returns all their entries in order. Equal keys within a half keep their relative order by the same argument applied to the smaller call; across halves, every left entry originally preceded every right entry, so taking left first preserves stable sorting. Both half-lengths decrease for , establishing termination.
Minimum forward-jump dynamic programming Created 2026-10-31 Updated 2026-11-05
For nonnegative maximum jump lengths in an array, let and let unreachable positions have value . Classifying a route to by its penultimate position proves this dynamic programming recurrence. Increasing is a valid dependency order because every jump advances. Scanning all previous positions uses time complexity and space complexity. Store a minimizing predecessor to reconstruct a shortest route.
Minimum stack 2026-10-31
A stack supporting access to its minimum in constant time complexity when its contents are nonempty. Each linked list node stores its value and the minimum of the suffix beginning there. Pushing computes one new cached minimum; popping reveals the previous cached minimum. Keeping one cached value per node handles repeated minima without a special case.
Missing-value search by deficient value intervals Created 2026-10-24 Updated 2026-10-31
Suppose a candidate integer interval contains possible values and an active array segment contains exactly all occurrences from that interval, with entries. The pigeonhole principle guarantees a missing value. Split the value interval into widths and use array partitioning to obtain occurrence counts . If , retain the left side. Otherwise , so retain the right side. This works with duplicate entries because it needs only the inequality between occurrences and possible values.
Balancing the value widths gives , while the active scan length remains less than . The total work is bounded by a geometric series and logarithmic loop overhead, hence time complexity. On reaching width one, the retained occurrence count is zero, proving that the sole candidate is absent globally. This is a binary search over deficient value intervals, with local in-place array partitioning, rather than repeated full-array scans.
Move ordering 2026-10-25
The order in which legal child positions are searched. Good move ordering supplies useful alternatives early and increases alpha-beta pruning; poor move ordering can leave the worst-case time complexity of full minimax search unchanged.
Neighbour enumeration 2026-10-14
Neighbour enumeration reports the neighbours of a specified vertex. For a simple graph, scan its adjacency list and report each entry. With constant-time list access and work per entry, a list of length needs time in Big O notation, conventionally written for nonempty lists. Use vertex degree for an undirected graph and outdegree for a directed graph. Obtaining the list reference can take constant time; consuming it requires visiting every entry.[ref]
In our undirected example, enumerating 's neighbours reads : three entries. Scanning row of the full adjacency matrix reads six entries, , to produce the same answer. In the directed variant, enumerating 's outgoing neighbours reads no neighbour entries, but still needs constant work to locate and recognize its empty list. For a multigraph, scanning lists enumerates incident edges with multiplicity; reporting only distinct neighbours additionally requires removing repetitions.
For a short time complexity argument, each reported entry requires at least one output operation, and one scan suffices. Across all vertices, the undirected entry count is by the handshaking lemma; the directed count is . A graph search that processes each vertex once and scans each of its entries once therefore does structural work, provided its visited-state access and FIFO queue or stack operations also have the required constant-time costs. With a full adjacency matrix, scanning every row instead inspects entries. This is how the representation enters the analysis of breadth-first search and depth-first search.
Number-theoretic sieve 2026-10-20
A number-theoretic sieve processes many integers together by marking or updating those sharing a divisor, rather than testing each integer independently. The sieve of Eratosthenes marks composite multiples of successive prime numbers; related sieves accumulate a smallest prime factor, Euler's totient function, or Möbius function for every argument up to a bound. The useful structure is that the multiples of a fixed integer form an arithmetic progression, so one loop can update all affected entries in an array.
For example, initializing an array to true and then marking for each surviving prime number leaves precisely the prime numbers unmarked, apart from the separately excluded zero and one. Every composite number has a prime factor, which proves that every composite is eventually removed. Starting the marking at avoids work already performed by smaller prime numbers. Different sieves use different update rules and time complexity bounds; the name alone does not imply the complexity of the sieve of Eratosthenes.
Yes: starting from zero, increments of the decimal counter cost digit changes, uniformly in the number of digits. An increment changes the trailing digits equal to into and increases the next digit. Number digits from at the least significant end. Digit changes once every increments, so the exact number of changes is
Here the floor function counts carries reaching each position, and the last equality sums a geometric series. Since digit changes on every increment, for . The loop tests and carry handling add only a constant amount per changed digit and per operation, giving the same time complexity.
An accounting method explanation is also possible. Charge two credits for each change of digit : one pays for that change and one joins a common bank. For increments the higher digits change at most times, so their costs can be covered from that bank; the displayed prefix bound ensures that it never goes negative.
The formula allows wraparound modulo ; alternatively, restrict to increments before overflow. Initializing the array itself costs if that is counted separately. If the initial digits are arbitrary, the number of changes at position is at most , giving in Big O notation. Starting with all digits equal to makes the first increment cost , so the initial-state convention matters.
Searching the dynamic chain would require identifying the procedure associated with each visited stack frame. More seriously, the search length is bounded by the number of active calls, not by lexical nesting depth. Recursion in procedures unrelated to the desired enclosing declaration can make arbitrarily large. Thus a single nonlocal variable access can take time complexity, whereas a conventional static chain access needs only traversals for lexical distance .
Instead give each procedure a known global pointer cell current[P]. On entry to , save its previous value in the new stack frame and set current[P] to the new frame pointer. On return, restore the saved value. A nonlocal variable declared in is then loaded using current[P] and its known frame offset. The proof in part (d) justifies that lookup in the absence of procedural parameters. This is a procedure-indexed version of a display for lexical scope; a conventional display for lexical scope can instead use lexical levels as indices.
With procedures and active calls, the procedure-indexed table needs additional global words and one saved previous pointer per active stack frame, hence activation storage. The saved word can replace the conventional per-frame static link if that link is no longer needed. A conventional static chain has one pointer per active stack frame and no such -entry table. Both schemes retain ordinary dynamic links and return information.
The table gives constant-time nonlocal access and constant-time save/restore work on each entry/return, independently of lexical distance. Conventional static chain access costs per access, and establishing the callee's static link may also require following an appropriate portion of the caller's chain. For a fixed program is statically bounded, but it still affects generated instruction counts. These costs assume constant-cost pointer operations and omit shared ordinary call overhead. For the procedure-indexed table,
is undecidable. The condition depends only on the accepted formal language. It holds for a Turing machine accepting the empty language, and fails for a Turing machine accepting the singleton , where is an alphabet symbol. It is therefore a nontrivial extensional property of programs, and Rice's theorem applies. In particular, the condition does not assert that the machine halts on every input; nonacceptance of long words over an alphabet may result from rejection or from an infinite computation.
is a decidable language: it consists of every valid Turing machine encoding. Every multitape Turing machine has an equivalent single-tape Turing machine. To see this, represent the finitely used portions of its tapes on one tape, separated by delimiters, and mark each simulated head position. To simulate one step, scan these portions to read the marked symbols, retain this fixed number of symbols and the control state in finite control, and scan again to update the symbols and head marks. Extend a represented portion with a blank cell when necessary. Each simulated step takes finitely many real steps.
The single-tape Turing machine accepts exactly when the simulated multitape Turing machine accepts; infinite computations remain infinite. The simulation may increase time complexity, but the question only asks about accepted formal languages. Hence a decider simply checks the syntax of the Turing machine encoding and accepts every valid description. Rice's theorem does not make this property undecidable, because the property is true of every computably enumerable language and is therefore trivial in the theorem's sense.
The linear speedup theorem concerns multitape Turing machines whose finite control and tape alphabet may change. Formally, for , if a deterministic -tape Turing machine decides within steps on every input of length , then for every constant there is a deterministic -tape Turing machine deciding the same formal language with
The additive constant is independent of ; in the usual normalized formulation the bound is , with the integer-rounding convention absorbed in the constant.[ref]
The construction packs a fixed number of old tape symbols into each new symbol and uses a larger finite control to simulate blocks of old steps. Initial input packing explains the additive linear term. If , choosing a larger constant makes the total asymptotic time complexity an arbitrarily small constant multiple of .
It does not promise arbitrary speed increases on fixed hardware. Larger packed symbols and transition tables cease to be single constant-cost hardware operations without limit. The theorem also retains the input-reading overhead. It is a statement about changing the abstract machine description and primitive operations, rather than an unlimited implementation optimization on one processor.
The clique decision problem belongs to NP. First reject . Otherwise a complexity certificate lists distinct vertices. Check distinctness and test that each of the pairs is an edge. Under a conventional explicit graph encoding, the complexity certificate length and verification time complexity are polynomial in the input length. The early rejection is relevant when is given in the binary numeral system.
For NP-hardness, first transform a SAT instance into an equisatisfiable conjunctive normal form of polynomial size using a Tseitin transformation. This step avoids the possibly exponential increase caused by distributing arbitrary Boolean formulas into conjunctive normal form. Introduce a fresh Boolean variable for each subformula, constrain it to have the connective's truth value using a constant number of Boolean clauses, and require the top variable to be true. A Boolean valuation of the original Boolean variables satisfies the original Boolean formula exactly when it extends to a satisfying assignment of these constraints.
Create one vertex for each occurrence of a Boolean literal in each Boolean clause. Join two such vertices by an edge exactly when they belong to different Boolean clauses and their Boolean literals are not a variable and its logical negation. Set . There are at most as many vertices as Boolean literal occurrences and at most quadratically many edges, so this construction takes polynomial time.
If has a satisfying assignment, choose one true Boolean literal occurrence from each Boolean clause. No two selected Boolean literals are contradictory, so their vertices form a clique. Conversely, an -clique contains at most one vertex from each Boolean clause, because there are no edges within a Boolean clause. It therefore selects exactly one occurrence from each of the Boolean clauses. The selected Boolean literals are pairwise noncontradictory, so assign their Boolean variables the indicated truth values and assign any other Boolean variables arbitrarily. This Boolean valuation satisfies every Boolean clause.
An empty Boolean clause gives no vertex in its group, correctly preventing an -clique. An empty logical conjunction can instead be mapped to a fixed yes-instance, avoiding any convention about . Malformed SAT descriptions can be mapped to a fixed no-instance. We have proved
The binary numeral system representation is taken to be canonical, with no leading zeroes, for each positive integer. Delimiters separate the components of a pair or triple. Syntax, positivity and this representation convention can all be checked in logarithmic space. The useful principle is that a large integer need not be stored in order to compute its digits one at a time.
First consider Add. Let denote the binary digits in position , counting from the least significant position and taking out-of-range digits to be zero. Count the component lengths, and let be their maximum. Start with arithmetic carry . For , compute
Reject if at any position. After the last position, reject if ; otherwise accept. The final arithmetic carry check prevents accepting a result with an omitted high digit, such as the false equality obtained by retaining only two binary digits.
The binary-addition carry invariant is
It holds initially and is preserved by the displayed one-column equations. At the end, it proves that the comparisons and the final arithmetic carry check succeed exactly when . Each requested binary digit is recovered by scanning the corresponding input field and counting to its position. The length counters, position and scan counters require bits, while and require constant space. Thus
For Pal-Add, construct a logspace transducer producing the canonical binary numeral system representation of . Put . One least-to-most-significant pass using the same recurrence determines the final arithmetic carry . Positivity and canonical representations imply that the sum's digit length is
Indeed, one summand is at least and both are less than . For each output position, from down to , recompute the required sum digit from scratch: reset the arithmetic carry to zero and run the column recurrence from position up to the requested position, reading input digits by scans. Positions beyond the summands use zero digits, so position correctly emits the possible final arithmetic carry. Emit only the requested digit, then reuse the work space for the next position.
This produces most-significant-first output with digits. It uses work space because it retains only a fixed number of digit indices, lengths, scan counters and one arithmetic carry; it never stores the whole sum. A direct implementation with repeated whole-input scans uses at most time complexity, which is sufficient here. Hence is a logspace-computable function.
Finally simulate the assumed L decider for binary palindrome on this virtual output, using logspace composition by recomputation from part (b). Whenever the simulated input head asks for a digit, rerun the addition logspace transducer until it emits that digit. The virtual input length is , so both its work space and the addition work space are . The simulation accepts exactly when the canonical representation of is a binary palindrome. Therefore
Equivalently, one could directly compare the sum digits in positions and , recomputing each digit by the same recurrence. This gives the same logarithmic space conclusion without ever writing the full sum on a work tape.
An embedding is determined by its chosen increasing sequence of positions. Accordingly, the all-subsequence embedding kernel counts pairs of embeddings, one in and one in , that spell the same subsequence. The two embeddings are distinguished even when they spell the same word as another pair. The empty word contributes exactly one pair.
Let , , and define for prefixes. When either prefix is empty, only the empty word has an embedding in both, so
To derive a dynamic programming recurrence, count pairs that do not use position of or do not use position of . Inclusion-exclusion gives
The remaining pairs use both final positions. These positions must be the final letters of the common word, so they contribute nothing if . If , deleting those two final positions is a bijection to arbitrary embedding pairs on the two shorter prefixes, including their empty pair. Their contribution is therefore . Hence
Equivalently, when the final symbols agree the recurrence simplifies to ; when they differ, subtract the diagonal term. Fill the table in increasing prefix order and return . The boundary values and the disjoint counting argument prove correctness by induction on .
A one-row implementation of this dynamic programming uses the saved old diagonal entry:
F[0..p] := 1
for i := 1 to n:
    diagonal := 1
    for j := 1 to p:
        above := F[j]
        if x[i] = y[j]:
            F[j] := above + F[j-1]
        else:
            F[j] := above + F[j-1] - diagonal
        diagonal := above
return F[p]
The assignment to diagonal retains the value from the previous row before F[j] was overwritten. Swapping and if necessary minimizes the row length. Thus the time complexity is arithmetic operations and the extra space complexity is integer cells. Empty inputs return one immediately.
These counts include multiplicity: for , the empty word contributes , the word contributes , and contributes , giving , not three. More generally, each result is at most , since it counts some pairs of position subsets. Exact integers therefore require bits; the stated quadratic bound is an arithmetic-operation bound, with a conservative bound for elementary bit arithmetic.
The proposed positive-semidefinite kernel is valid: for each finite string only finitely many coordinates are nonzero, so is a well-defined feature map into the inner product space of finitely supported coordinate families, and its inner product is exactly .
The two-interval approximation by one interval supplies an approximation guarantee for every input probability distribution . Merge overlapping target intervals, and write the target positive set as at most two disjoint ordered intervals . Put and . If there is only one nonempty component, the target already belongs to the interval hypothesis class and has zero misclassification risk. If the interval notation permits empty intervals and the target is empty, choose that same empty interval in .
In the two-component case, choosing the heavier component as the hypothesis loses only the lighter component, so its misclassification risk is
Alternatively, choose the single interval spanning both components. This produces no false negatives, and its false positives lie in the gap. Its misclassification risk is at most . Both candidates are in , so there exists an interval with
For the last step, use if , and if . This avoids any assumption that an empty interval or the whole real line belongs to .
Use empirical risk minimization over intervals on independent labelled examples. The generalization result needed here is the VC uniform convergence theorem: for a binary hypothesis class of finite VC dimension , there is a universal constant such that, for any labelled-data probability distribution and , a sample size
ensures, with probability at least , that every hypothesis's empirical misclassification risk differs from its misclassification risk by at most . This theorem does not require the labels to be realizable by the hypothesis class.[ref]
The interval hypothesis class has VC dimension two: any two ordered points can receive all four labellings, whereas an interval cannot label three ordered points . Take and choose an interval minimizing the empirical misclassification risk. On the simultaneous convergence event,
Therefore
Since and are fixed constants, examples suffice, which is polynomial in as required by the paper's definition of weak PAC learning.
For completeness, empirical risk minimization over intervals is computationally effective. Sort the sample and group equal coordinates, since one interval cannot split identical inputs. Give each group weight equal to the number of positive labels minus the number of negative labels in that group. The number of empirical mistakes made by an interval is the total number of positives minus the total weight of the consecutive groups it contains. Select the consecutive block of maximum weight, or select a finite interval outside the sample if every nonempty block has negative weight. This enumerates all possible sample labellings by intervals and attains the minimum empirical misclassification risk; sorting and a maximum-block scan are sufficient. The time complexity is .
Use weighted decision stump optimization with the convention , and write . For each coordinate , sort the examples by their th coordinate and group all equal coordinate values. For a threshold between the th and st distinct values, the decision stump predicts on the left and on the right. Its weighted misclassification risk is
Start with a threshold below the minimum observed value. Every prediction is then , and the initial error is . Sweep the threshold from left to right. When it passes an entire group of equal coordinate values, that group's prediction changes from to , so update
Record the smallest value and a threshold achieving it, including the final threshold above all observations, which predicts everywhere on the sample. Representatives can be chosen strictly between successive distinct values; the two outer representatives are finite real numbers below the minimum and above the maximum.
Every threshold has exactly the same sample predictions as one of these representatives. In particular, if a threshold equals an observed value, the equality group is on the side under the chosen sign function convention, which duplicates the representative immediately before that group. Thus the sweep includes every possible sample labelling by the stated decision stump. Repeating for all coordinates and returning the globally smallest error proves optimality.
Sorting costs per coordinate and the grouped sweep costs . The overall time complexity is
with working storage when coordinates are processed one at a time. Pre-sorted coordinate orders can be reused across repeated AdaBoost rounds, leaving work per round for changing weights. The paper allows only the orientation ; reversing its polarity would enlarge the hypothesis class and is unnecessary here.
Brick boundaries are not observable in the requested row equality. Two adjacent red width-one bricks must compare equal to one red width-two brick at the same left coordinate. Comparing the underlying placement lists would therefore give the wrong result.
Instead build each row's unique sequence of maximal occupied colour runs: merge adjacent placements exactly when they touch and have equal colours. Gaps remain gaps, and touching different colours remain separate runs. This is a geometric version of run-length encoding, with explicit start and end coordinates. Insert these members inside Row from part (d):
private static final class Run {
    final long x, end;
    final Color colour;

    Run(long x, long end, Color colour) {
        this.x = x;
        this.end = end;
        this.colour = colour;
    }
}

private List<Run> runs() {
    List<Run> result = new ArrayList<Run>();
    for (Placed b : bricks) {
        int last = result.size() - 1;
        if (last >= 0) {
            Run r = result.get(last);
            if (r.end == b.x && r.colour.equals(b.colour)) {
                result.set(last, new Run(r.x, b.end, r.colour));
                continue;
            }
        }
        result.add(new Run(b.x, b.end, b.colour));
    }
    return result;
}

@Override public boolean equals(Object other) {
    if (this == other) return true;
    if (!(other instanceof Row)) return false;
    List<Run> a = runs(), b = ((Row) other).runs();
    if (a.size() != b.size()) return false;
    for (int i = 0; i < a.size(); ++i) {
        Run r = a.get(i), s = b.get(i);
        if (r.x != s.x || r.end != s.end || !r.colour.equals(s.colour))
            return false;
    }
    return true;
}

@Override public int hashCode() {
    int h = 1;
    for (Run r : runs()) {
        h = 31 * h + Long.hashCode(r.x);
        h = 31 * h + Long.hashCode(r.end);
        h = 31 * h + r.colour.hashCode();
    }
    return h;
}
Color.equals compares colour values rather than object identity. Two row snapshots compare their local horizontal content independently of which wall height supplied them. Empty rows compare equal, even if obtained from different walls. The hash code uses the same canonical runs as equals, so alternative brick subdivisions with equal displayed content also have equal hash codes.[ref]
To prove correctness, observe that a maximal run starts whenever occupancy begins or the colour changes, and ends exactly where that occupancy or colour ceases. Those boundaries are determined by the occupied colour at every coordinate. Thus equal occupied colours give the same runs, and equal runs give equal occupied colours. If rows contain and bricks, generating and comparing their runs has time complexity and additional storage, independent of their widths or the magnitude of their coordinates. This meets the requirement to improve on checking every possible cell:
A binary search tree is a binary tree storing distinct keys from a total order, with every key in a node's left subtree smaller than that node's key and every key in its right subtree larger. The condition concerns entire subtrees, not just immediate neighbours.
For membership, start at the root of a tree and compare the target with the current key. Return true on equality; continue into the left subtree for a smaller target and the right subtree for a larger target; return false on an empty subtree. The binary search tree ordering ensures that a discarded subtree cannot contain the target. Each step descends one level, so the algorithm terminates and uses time complexity for height of a binary tree , under constant-time key comparison.