Use Turing machines with a two-way read-only input tape, bounded by endmarkers, and a fixed finite number of read-write work tapes over a fixed finite alphabet. Work-tape cells count towards space complexity; the read-only input does not. For input length , use to include the small-length cases.
, or L, is the class of formal languages decided by a deterministic such machine using at most work-tape cells for some fixed constant . It must halt on every input and accept exactly the members.
, or NL, is the class of formal languages accepted by a Nondeterministic Turing machine with the same work-space bound on every computation branch. An input is accepted if and only if at least one branch accepts. One may require all branches to halt: the configuration graph has only a polynomial number of vertices, so a logarithmic space counter can stop any branch that has taken more steps than that bound. If an accepting computation exists, one exists with no repeated Turing machine configuration, so this convention does not change the complexity class.
In standard space complexity notation,
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 .
Depth-first search computes minimax search values with much less live storage and naturally supports alpha-beta pruning. A parent's value needs only its current best child value and the next child to visit. Once a child subtree has been evaluated, its internal search nodes can be discarded; a final value cannot usually be computed from a nonterminal frontier alone.
With branching factor and horizon , breadth-first search stores a frontier of order . A depth-first search implementation storing sibling lists uses space complexity; lazy successor generation can reduce this to frames plus game-state storage. Both unpruned traversals have time complexity for . Depth-first search also supplies a completed sibling outcome early, allowing alpha-beta pruning to reject later subtrees before generating them.
Computational complexity theory studies the resources needed by an algorithm as a function of input size, after specifying the resource and computational model. For example, time complexity may count comparisons, and space complexity may count stored words. Worst-case time complexity is the greatest cost among inputs of size ; best-case and average costs are different measures.
An upper bound guarantees that a cost is no greater than the stated bound. A lower bound guarantees that it is no smaller. For a problem, an algorithm can establish an upper bound on what is achievable, while a problem lower bound must apply to every eligible algorithm in the chosen model. Bounds need not be tight. Concisely,
Divide-and-conquer algorithms suit problems with largely independent, balanced subproblems and an inexpensive combination step. In merge sort, the two halves are independently sorted and merged in linear time. Its recurrence relation is , giving time complexity.
Dynamic programming suits overlapping subproblems with a compact state description. For the coin change problem, let be the minimum number of coins needed to make amount . With positive denominations containing ,
Every optimal nonempty answer has a last coin and an optimal answer for ; otherwise replacing the remainder improves it. Filling takes time complexity and space complexity. Repeated amounts are computed just once. This bound is in the numeric amount , not its binary input length.
A greedy algorithm suits problems where one can prove a greedy-choice property. For unweighted interval scheduling, choose an interval with earliest finishing time, discard overlapping intervals, and repeat. Among optimal schedules, replace the first interval by the earliest-finishing one. The replacement finishes no later, so every later interval remains feasible. Applying the same argument to the remaining intervals proves optimality. After sorting by finish time, a single scan suffices.
These examples separate the relevant structural reasons: independent halves, repeated amount states, and an exchange argument certifying each irreversible choice.
Heapsort uses time for bottom-up heap construction and for each extraction, giving worst-case time complexity. An iterative heapify down on an array uses auxiliary space complexity. Ordinary heapsort is not a stable sorting method.
Quicksort has balanced-case and average-case time complexity when the input order supplies suitably distributed pivot ranks. With the prescribed first-element pivot, sorted inputs produce subproblems of sizes and , giving . With the stated two-way partition convention, all-equal keys also give this worst case. There is no input-independent expected bound without a distribution or randomization assumption. For an in-place array implementation, the recursion stack is when balanced and in the worst case; the functional list trace also allocates new partition spines and copied concatenation prefixes. Ordinary in-place quicksort is not stable sorting; the stable-partition list convention used in the trace can preserve equal-key order at additional allocation cost.
Counting sort uses time complexity for possible consecutive integer keys. The stable sorting version uses auxiliary space complexity including the output array; counting and re-emitting bare keys needs only beyond its output. It is attractive when is small, but a sparse huge key range makes both initialization and count storage expensive. It relies on indexing by bounded integer keys, so it is not subject to the comparison sorting lower bound.
Each merge consumes and copies a total of elements, so its time complexity is . Hence
At any level of the recursion tree, all active subranges are disjoint and together contain at most elements. The total work per level is therefore , and halving gives levels. In fact the full run performs work for .
The shared work array holds elements, and the depth-first recursion has simultaneous activation records with a constant number of scalar variables each. No recursive call allocates a fresh array. Therefore
The work array is counted in the auxiliary space complexity even though the caller supplies it. If its actual allocated capacity is , the reserved storage is ; choosing capacity gives the stated bound.
Store pred[j] = i whenever a strict improvement sets D[j] = D[i] + 1. Initialize predecessors to NONE. After the dynamic programming pass, return NONE if the final position is unreachable; otherwise follow predecessors backwards:
route = []
j = n - 1
while j != 0:
    route.append(j)
    j = pred[j]
route.append(0)
reverse(route)
return route
Every stored predecessor is smaller than the current index, so reconstruction terminates. Its stored distance is exactly one smaller, so the output has precisely jumps and each jump satisfies its input bound. Therefore . Reconstruction takes additional time complexity and output space; the total dynamic programming bounds remain time and space complexity. Keeping the first predecessor on ties selects one optimal route deterministically.
Use unit-cost insertion, deletion and substitution of one symbol. Their minimum total cost is the edit distance. Let be the edit distance between the first symbols of the first sequence and the first of the second. Initialize and . For compute
The cases delete the final source symbol, insert the final target symbol, or align the two final symbols, paying one for substitution and zero for a match. Every optimal alignment ends in one of these cases, and each case extends a valid shorter alignment. Induction on proves the dynamic programming recurrence correct.
Fill rows or columns in increasing order so every dependency is already available. There are entries with constant work per interior entry: running time for nonempty sequences, or including the boundary cases. The full table has space complexity ; two rows give auxiliary space when only the distance is wanted. Predecessor choices in the full table recover an optimal edit sequence.
During the computation in part i, record an index attaining the minimum at every positive amount. Starting with , print and replace by , continuing until .
Every step decreases the amount and reduces the table entry by exactly one. The printed denominations therefore sum to and their number is exactly , proving optimality. The total running time is , including the output; because denomination is available. The predecessor array adds to the space complexity. This is reconstruction from the dynamic programming certificate, not the largest-denomination greedy algorithm, which need not be optimal for arbitrary denominations.
For nonnegative integer amount , let be the minimum number of coins making amount . Set and compute, in increasing order of ,
An empty candidate set has minimum . Here denomination ensures that every nonnegative amount is attainable. Removing one coin from an optimal nonempty solution gives a smaller amount, and adding any allowed last coin gives a feasible solution; these two directions prove the recurrence by induction on .
Return whether . This solves the at-most- decision without needing a separate dimension for . The table for the minimum coin change recurrence takes running time and space complexity. The bound is pseudopolynomial time: the amount, rather than its binary encoding length, appears in it. Amount zero needs zero coins.
Use the multiplicative score exactly as defined in the paper. Let be the largest score of a matching length- route ending at . Initialize and mark all other entries unreachable. For each stage, clear the new layer and inspect matching edges from reachable entries:
An empty candidate set is marked unreachable, rather than given score zero: a genuine route may have score zero. A Boolean reachability table or a sentinel with a guard before multiplication distinguishes the cases. Store the maximizing predecessor edge at each reachable layer entry, retaining one on a tie.
Multiplication by a nonnegative edge factor preserves order, so replacing a prefix by a larger-scoring matching prefix cannot worsen its extension. Induction proves this maximum-product edge-labelled walk recurrence correct. Choose a reachable final entry of greatest score and follow its layer-indexed predecessors backwards to reconstruct the answer. If no final entry is reachable, report that no matching route exists, even though all numeric scores might otherwise look like zero.
The running time is , and rolling scores have space complexity , while retaining all reconstruction pointers gives space complexity . For the vertex-simple interpretation, retain the visited set in each state as in part i, prohibit revisits and maximize the same products over those states. This exact exponential-state variant preserves both the zero-score distinction and predecessor reconstruction. If the starting vertex is unrestricted rather than inherited from part i, initialize for every vertex. The calculation needs no independence assumption beyond the paper's definition of a product score; repeated physical edge-activation events would require a separate probabilistic model.
The printed formula for the edge label has mismatched variable names. The type-correct reading is . Interpret the requested route as a directed walk of consecutive labelled edges, allowing repeated vertices; the distinction from a vertex-simple directed path is discussed below.
Let be the set of vertices reachable from the specified start after reading exactly the first labels. Initialize and update
After stages, answer yes exactly when . A directed walk realizing a prefix decomposes into a walk realizing the shorter prefix and one correctly labelled final edge; conversely every such extension is valid. This proves the dynamic programming invariant by induction on . Store reachable vertices in Boolean arrays and scan the edges per stage. The running time is with rolling-table space complexity, in addition to graph storage. The empty label sequence is realized by staying at .
If “path” is instead required to mean vertex-simple, augment the state to , where is the set of visited vertices. Start with and extend a matching edge to only when , replacing by . This gives an exact dynamic programming algorithm for that interpretation too; reject immediately when . A straightforward bound is running time with rolling-table storage. The exponential distinction is substantive: all labels equal and include the Hamiltonian path problem from a fixed start. The efficient layered recurrence answers the consecutive-edge interpretation without pretending to enforce distinct vertices.
Let a be the given enclosing array. A two-way array partition needs only one scan, and does not require the pivot to occur in the array:
def partition(l: Int, r: Int, p: Int): Int = {
  require(0 <= l && l <= r && r <= a.length)
  var k = l
  var j = l
  while (j < r) {
    if (a(j) < p) {
      val t = a(k)
      a(k) = a(j)
      a(j) = t
      k += 1
    }
    j += 1
  }
  k
}
The loop invariant is , every entry of is less than , every entry of is at least , and the segment's multiset is unchanged. Entries outside are unchanged. When a(j)<p, swapping it into position k extends the low part; if k<j, the displaced entry was in the high part and remains there after j advances. If k==j, the self-swap is harmless. The other branch simply extends the high part. The loop variant is . At exit , so the returned has the required separation property, including empty segments and arbitrarily many duplicate entries. The time complexity is and auxiliary space complexity is .
Keep a deficient interval of possible values and only the array segment containing occurrences from that interval. This is missing-value search by deficient value intervals:
def missing(): Int = {
  val n = a.length
  var lo = 0L
  var hi = n.toLong + 1L
  var l = 0
  var r = n
  while (hi - lo > 1L) {
    val p = lo + (hi - lo) / 2L
    val k = partition(l, r, p.toInt)
    if ((k - l).toLong < p - lo) {
      hi = p
      r = k
    } else {
      lo = p
      l = k
    }
  }
  lo.toInt
}
The precondition is that every original entry lies in . The loop invariant is
together with: every active entry lies in , and every original occurrence with a value in that interval is in the active segment. The whole array remains a permutation of its initial contents. Initially these assertions follow from the precondition and .
After array partitioning, the low subinterval has occurrences and possible values. If it is deficient, retaining it preserves the loop invariant. Otherwise , while the original active count is strictly less than ; subtraction gives
Thus the high subinterval is deficient and retaining it also preserves the loop invariant. Discarded occurrences lie outside the new candidate interval. The loop variant is the positive integer , which strictly decreases because the midpoint is strictly internal. At exit the interval has one possible value and fewer than one occurrence, so lo is absent from the entire original array. For the loop is skipped and zero is returned. The Long value bounds avoid overflowing ; every internal pivot is at most , so its checked mathematical range fits Int.
For the time complexity, let be the interval width and its active occurrence count before iteration . The loop invariant gives , and binary search gives . Each two-way array partition costs . Until the width reaches one, the widths are bounded by , so the total scan work is bounded by a geometric series plus loop overhead: overall, hence for positive . Partitioning the full array again at every iteration would instead lose this bound. Auxiliary space complexity is .
Let the abstract state be the set of occupied coordinate pairs. For the Boolean array, the abstraction function is . Its representation invariant requires an Boolean array and the downward-closure property
Thus is an order ideal for the coordinatewise partial order. Removing an upper-right rectangle preserves this property. The empty set is allowed after the losing move.
For the row-boundary array, the abstraction function and representation invariant are
The array has length . Removing at replaces each row(j) for by . Earlier rows are unchanged. This both implements the abstract removal and preserves the nonincreasing boundary.
Without a cached count, the Boolean representation takes for Count, for Legal, worst-case for Move, and for a full-grid Display. The boundary representation takes for Count, for Legal, worst-case for Move, and for the same full-grid Display. Their space complexities are respectively and . A scalar cached total makes Count in either representation if each move updates it consistently. The implementation below uses that cache with the boundary array, so it achieves constant-time Count and Legal, linear worst-case Move, and linear storage. Full-grid output still takes quadratic time because it emits quadratic many cell positions.
Persistent data structure Created 2026-10-24 Updated 2026-10-31
A data structure whose previous versions remain usable after an update. An immutable representation can return a new root while retaining old roots. Persistence is a version-availability property; it does not require copying the whole structure, and it does not by itself guarantee a particular time complexity or space complexity.
Path copying in a balanced tree can preserve old versions while allocating only the updated root-to-leaf path. A linked list can share an unchanged suffix but may copy a long prefix for a positional edit. Retained versions extend the lifetime of their reachable data, which matters when comparing snapshot history with edit-specific inverse commands.
Proof complexity 2026-11-05
Proof complexity measures resources needed to express proofs in a specified propositional proof system. Typical quantities include the total number of symbols, the number of inference steps and the space needed to retain intermediate formulas. A short theorem statement can require a much longer proof, and changing the allowed rules can change the required length dramatically.
For example, a resolution refutation of an unsatisfiable clause set derives the empty clause by resolving pairs of clauses on opposite literals. Verifying a supplied derivation is a local computation on its lines; searching for those lines can be much harder. A lower bound must therefore identify the proof rules and the family of clause sets to which it applies.
More generally, a propositional proof system can be represented by a polynomial-time computable map whose range is exactly the propositional tautologies. Every tautology then has a proof, and every produced formula is valid. If one such system had polynomial-length proofs for every tautology, tautologies would have polynomially checkable certificates, implying . Conversely that equality would provide such a certificate-based system. This connects proof length to computational verification.
Space complexity Created 2026-09-24 Updated 2026-11-05
The space complexity of an algorithm measures the maximum working storage used during its computation as a function of encoded input length. A machine-level definition must state which storage counts. In a common Turing machine convention, a read-only input tape and a write-only output tape are excluded, while visited work-tape cells are counted.
For example, count the ones in a binary string of length by scanning once and retaining a binary counter. Its value ranges from zero to , requiring bits for the counter. Keeping a separate copy of the full input would instead require bits. The computation can therefore use much less working storage than the amount of data it examines.
The maximum concerns simultaneously retained storage, not the total amount allocated and later reused over time. Bit complexity and a unit-cost model also need care here: treating an arbitrarily large integer as one storage cell can hide its growing representation size.
Stable digit sort 2026-10-18
A stable digit sort applies stable sorting to complete sorting records using one specified numerical digit of their encoded sort keys. Counting sort can supply it; stable record placement in counting sort moves records without discarding their associated data. Stability concerns equal current numerical digits, even when the full sort keys differ. This is the information-preservation step in least-significant-digit radix sort.[ref]
An original two-record counterexample exposes the need for the tie rule. Start with at width three. A units pass gives . Both tens numerical digits are four. A deliberately unstable tens pass may reverse their tie and return : it is sorted by the tens numerical digit, yet its two-position suffixes are decreasing. The final stable hundreds pass sees two zeros and keeps this wrong order. Sorting permutation preservation still holds, but sortedness fails. Stability in the tens pass would have retained the units information.
With counting sort as the stable digit sort, each pass initializes counters, counts current numerical digits, constructs their prefix sums, and places complete sorting records. Thus each pass costs , and passes cost in Big O notation. Reuse the counters and two arrays of record references between passes: auxiliary space complexity is , rather than . Assume constant-cost numerical digit extraction, counter arithmetic, array indexing and record-reference movement; the bound counts these operations, not the cost of copying arbitrarily large payloads or performing arbitrary-precision integer arithmetic.
The benefit is avoiding a counter for every possible whole sort key: width has possibilities, while each pass needs only counters. A larger radix reduces the number of passes for a fixed key range but enlarges the counter array. The comparison sorting lower bound does not apply to these direct array indices; they reveal more than a two-way comparison. Nor does fixing make disappear: growing key width still increases work.