Search only the suffix strictly after each candidate first index. This enforces distinct indices even when the target is twice an existing value. Compute the complement in Long to prevent integer overflow: subtracting two Int values can require 33 signed bits.
def twoSum(a: Array[Int], target: Int): (Int, Int) = {
  def lowerBound(from: Int, wanted: Long): Int = {
    var lo = from
    var hi = a.length
    while (lo < hi) {
      val mid = lo + (hi - lo) / 2
      if (a(mid).toLong < wanted) lo = mid + 1
      else hi = mid
    }
    lo
  }
  var i = 0
  while (i < a.length - 1) {
    val wanted = target.toLong - a(i).toLong
    val j = lowerBound(i + 1, wanted)
    if (j < a.length && a(j).toLong == wanted) return (i, j)
    i += 1
  }
  (0, 0)
}
The outer loop invariant says that no solution has a smaller first index than i, when a pair is written in increasing index order. A failed suffix binary search proves there is no partner for the current i, extending the excluded prefix by one. A successful return has and in exact integer arithmetic. At exhaustion, every possible ordered pair has been excluded, so the sentinel (0,0) means no solution. The inner loop invariant is the standard lower-bound partition, restricted to the suffix starting at i + 1.
There are at most suffix searches, each taking running time, so the total is , customarily written for . Auxiliary space is . Empty and singleton arrays immediately return the sentinel. This is distinct-index two-sum by suffix lower bounds; a faster two-pointer technique is also possible on a sorted array, but the code here directly meets the requested search-based bound.
For the given sorted array, the complete lower-bound search behavior is for , for , for , and for . In particular, index is never the correct answer because the two equal entries share the same first insertion position.
These unit tests cover every value boundary, equality case and missing-value interval:
  • Below all entries, including the smallest machine integer: ternarySearch(a, Int.MinValue) == 0 and ternarySearch(a, 0) == 0.
  • Equality with the first entry: ternarySearch(a, 1) == 0.
  • Values in the first gap: ternarySearch(a, 2) == 1 and ternarySearch(a, 3) == 1.
  • Repeated equality must return the first duplicate: ternarySearch(a, 4) == 1.
  • Values in the second gap: ternarySearch(a, 5) == 3 and ternarySearch(a, 9) == 3.
  • Equality with the final entry: ternarySearch(a, 10) == 3.
  • Beyond the final entry: ternarySearch(a, 11) == 4 and ternarySearch(a, Int.MaxValue) == 4.
For every tested target, also assert that the array is unchanged, the result lies in , every entry before it is strictly smaller, and every entry from it onward is at least the target. These postconditions check the intended partition directly rather than merely accepting any equal occurrence.
This is lower-bound search: return the first position whose value is at least the target, allowing the result to equal the array length. The notation for an empty suffix is vacuously true, so this also covers a target larger than every entry and the empty array. Assume a stable sorted array, ordered nondecreasingly.
def ternarySearch(a: Array[Int], x: Int): Int = {
  var lo = 0
  var hi = a.length
  while (lo < hi) {
    val third = (hi - lo) / 3
    val m1 = lo + third
    val m2 = hi - 1 - third
    if (a(m1) >= x) hi = m1
    else if (a(m2) < x) lo = m2 + 1
    else {
      lo = m1 + 1
      hi = m2
    }
  }
  lo
}
The loop invariant is
Initially the excluded prefix and suffix are empty, so both quantified assertions hold. During an iteration, . If , sortedness makes every later value at least , so replacing hi by m1 preserves the right assertion. If the first test failed and , every earlier value is below , so replacing lo by m2 + 1 preserves the left assertion. Otherwise ; both new exclusions are valid, and lo = m1 + 1; hi = m2 retains exactly the unresolved middle. In that branch , since a single value cannot satisfy both strict and nonstrict inequalities in opposite directions.
The nonnegative loop variant hi - lo strictly decreases. In fact, with old length and , the three possible new lengths are , with the middle branch feasible only when nonnegative; each is at most . At exit lo == hi, and the loop invariant is exactly the desired partition. The result is the unique lower-bound index, including the first equal entry when duplicates occur. This ternary lower-bound search uses comparisons and auxiliary space, in the Big O notation word-operation model. The index formulas also avoid computing an overflowing 2 * length.
The proposed condition is not a loop invariant at the loop head. It holds initially and on entry to every executed body, but the iteration starting with i == 10 finishes with i == 11. Control then returns to the condition with the proposed upper bound false. A suitable numerical loop invariant is . If the number of printed lines matters, strengthen it to “exactly lines have been printed.” At exit, this and i > 10 give exactly ten printed lines. The nonnegative loop variant decreases by one on every iteration.
A loop invariant is a property of the program state that holds whenever control reaches the loop's condition, including the final failed test. Its main purpose is proving partial correctness: establish it initially, prove one guarded iteration preserves it, then combine it with the negated condition to obtain the postcondition. A separate loop variant or another progress argument proves algorithm termination and hence total correctness.
Recursively partition into equal halves by rank, keeping the selected median in the lower half:
quantiles(A,k):
    if length(A) == k:
        return [maximum(A)]
    p = select the (length(A)/2)-th smallest element of A
    L = all elements of A at most p
    R = all elements of A greater than p
    return quantiles(L,k) followed by quantiles(R,k)
All elements are distinct, so both halves have exactly elements. Since remains a power of two, every internal split occurs at a rank divisible by .
For correctness, the desired ranks in the lower half are . In the upper half they are the same local multiples of , shifted by . These are exactly all desired global ranks. At a leaf of size , its maximum is its sole requested local rank. Induction therefore proves that the output contains every requested order statistic, in increasing order, including the original maximum. There is no separate internal-node output of p, which would duplicate a rank already supplied by the lower subtree.
Use a worst-case linear-time selection algorithm and linear partitioning. The divide-and-conquer algorithm has
There are internal levels, each with total work , and leaves with total work . Since the source assumes , the running time is
This is multiselection by balanced rank partitioning. In-place selection and partitioning can use the original array; the output has values. The multiselection recursion has depth ; the selection routine contributes its own auxiliary storage.
Let . After each linear-time selection algorithm and partition, exactly elements are removed, so the successive input sizes are . Thus the standard efficient implementation takes
Here selection can use median of medians for worst-case linear time; a suitable randomised linear-time selection routine gives the same bound in expectation. Merely sorting each remaining array would introduce an avoidable logarithmic factor.
, approximately , arithmetic operations. Strassen's algorithm replaces an matrix multiplication by seven products of half-size blocks and a constant number of block additions and subtractions. Consequently
The Master theorem applies with , , since . Padding an arbitrary matrix dimension to the next power of two changes the dimension by less than a factor of two and preserves this asymptotic bound. The cost model counts scalar arithmetic as constant time; it is not a bit-complexity claim for arbitrarily large integer entries.
The three answers, in source order, are:
  • . In the Master theorem, , , and grows polynomially faster than . The regularity condition holds because . For powers of three, expansion even gives .
  • , and hence . The telescoping sum is .
  • . Set and . Then , with constant base cost for . The Master theorem with , applies because is polynomially smaller than . Finally .
The change of variable in the third case handles the additive shift in the recursive argument exactly; it is not an unjustified deletion of the +1. These Big theta notation conclusions use the usual admissible input sizes, or bounded integer rounding of subproblem sizes.
Repeatedly remove vertices whose current degree is less than . Implement the deletions with an adjacency list, a queue and a degree counter for each active vertex:
active[v] = True for every v
count[v] = degree(v)
queue all v with count[v] < k
while the queue is nonempty:
    remove v from the queue
    if not active[v]: continue
    active[v] = False
    for each neighbour u of v:
        if active[u]:
            count[u] -= 1
            if count[u] == k-1: queue u
return the subgraph induced by the active vertices,
       or report failure if there is no active vertex
The requested subgraph is understood to be nonempty; otherwise an empty output would make the degree requirement vacuous or undefined. For , any nonempty input graph already qualifies.
The correctness invariant is that every subgraph with minimum degree at least has all its vertices still active. Initially this is immediate. When is deleted, its degree in the whole active induced subgraph is less than . Any candidate subgraph on active vertices has at most that many incident edges at , so cannot contain it. Thus the invariant survives every deletion.
At termination, every active vertex has current degree at least , since every counter initially below the threshold or subsequently crossing it was queued. A nonempty surviving induced subgraph is therefore a valid answer. If none survives, the invariant rules out every possible answer, including ones omitting additional edges. The result is the k-core, with the k-core peeling invariant proving that deletion order cannot destroy a valid solution.
Each vertex is enqueued at most once when initially deficient or first crossing the threshold. Each adjacency list is scanned once when its vertex is deleted. The running time is , and storage is including the input graph.
Take
Its longest strictly increasing subsequences have length two. A subsequence starting with can continue with or with , but cannot use both in increasing order; one starting at has only after it.
The specified greedy algorithm may choose the longest increasing subsequence . The remaining sequence is , which needs two singleton increasing subsequences. The algorithm then uses three subsequences in total.
However, and partition the original sequence into two increasing subsequences. One is impossible because the original sequence is not increasing. Hence two is optimal and the greedy choice is suboptimal. This establishes the counterexample to removing a longest increasing subsequence without relying on a tie-breaking rule: the problem asks for a longest choice that can fail.
Write each undirected edge with its smaller endpoint first. Kruskal's algorithm orders candidates first by weight and then lexicographically:
Thus the requested addition order is
and the minimum spanning tree has total weight . Five accepted edges connect all six vertices, so the remaining weight-four edges need not be scanned.
The minimum spanning tree cut property says: if a cut of a graph respects an edge set contained in some minimum spanning tree, a minimum-weight edge across that cut is safe to add to , meaning that some minimum spanning tree contains together with that edge. Respecting means no edge of crosses the cut. In particular, any lightest cut edge belongs to some minimum spanning tree; a uniquely lightest cut edge belongs to every minimum spanning tree.
For the exchange argument, take a minimum spanning tree containing . If it lacks the chosen edge , add to create its fundamental cycle. The remaining route between 's endpoints crosses the cut at some edge , with . Since the cut respects , . Replacing by preserves a spanning tree, retains , and cannot increase weight. Hence it is also minimum. Strict inequality would contradict minimality, which gives the unique-lightest assertion.
For an illustration, take a triangle with weights , , . Across the cut , is the unique lightest edge and must be in every minimum spanning tree. The minimum tree is , of weight . With tied light edges, the existence assertion need not mean that every minimum spanning tree contains the particular tied edge chosen.
Let , , and let be the minimum number of words chosen from , in their given order, whose concatenation equals the length- prefix of a list of . Use for impossibility. The boundary values are
For ,
Here denotes indices . The first case omits . In the second, the last selected word is , so removing it leaves a solution using only earlier words for the shorter prefix. These are exhaustive alternatives. Conversely either alternative constructs a valid solution, proving the dynamic programming recurrence. Even an empty word causes no cycle because both alternatives use row .
Fill rows in increasing and store the chosen alternative for every finite entry. If , report no solution. Otherwise trace back from : a skip moves to ; a take records index and moves to . Reverse the recorded indices to obtain the required subsequence. Ties may choose either valid predecessor.
There are states. A substring comparison costs , so under the given bounds and the running time is , with storage including reconstruction choices. Two rows give working storage if only the optimum count is needed. For the source example, the optimum is three words, indices , whose concatenation is 010111. This is ordered word concatenation dynamic programming.
Sort the open intervals by increasing left endpoint. Scan them in that order, maintaining the largest right endpoint among previously seen intervals. For the next interval , report an intersection if ; otherwise set and continue. Equality is allowed: and do not meet because the intervals are open. For zero or one interval, return that they are mutually non-intersecting.
If , a previous interval with right endpoint has left endpoint at most and has positive length. Together with , this guarantees an interior common point. Conversely, if , every earlier interval ends at or before , so none intersects the new one. This loop invariant proves correctness. A comparison sort costs time and the scan costs .
For the lower bound, transform an input of integers for the element distinctness problem into
Equal integers produce identical, intersecting intervals. Unequal integers differ by at least one, so their intervals are disjoint. The answer therefore decides whether all the integers are distinct. Moreover, comparing any two constructed endpoints can be simulated by comparing their original integers and, only on equality, their fixed offsets or . Thus the transformation preserves the comparison model, rather than gaining extra information from arithmetic on arbitrary endpoints. The supplied distinctness lower bound gives comparisons, matching the upper bound. This is the comparison lower bound for interval disjointness.
First run breadth-first search, ignoring weights, to obtain the minimum number of edges from the source to each reachable vertex. Then compute weighted distances only along edges that advance one breadth-first layer:
d[source] = 0; all other d[v] = infinity
for u in nondecreasing BFS-layer order:
    for each outgoing edge (u,v):
        if h[v] == h[u]+1:
            if d[u]+w(u,v) < d[v]:
                d[v] = d[u]+w(u,v)
                predecessor[v] = u
Unreachable vertices keep distance . For an undirected graph, scan both orientations of each edge.
To justify discarding other routes, a shortest path can be taken simple because every weight is positive. A simple path of edges has weight in
Every path with at least edges weighs at least . Consequently every minimum-weight path must also have the minimum possible number of edges: this is minimum-hop dominance for nearly unit weights.
A minimum-hop path to uses exactly edges. Every prefix of such a path must itself have minimum hop count, since replacing a longer prefix by a shorter one would shorten the whole route. Hence it advances from layer to layer at every step. The retained edges form a directed acyclic graph, ordered by . The displayed dynamic programming recurrence therefore finds the cheapest of all minimum-hop paths, which by the preceding bound is a true shortest path.
Figure 1.
Disjoint weight bands for simple paths with different hop counts
. Details.
With an adjacency list, both the breadth-first search and the layer-ordered relaxations take time and total storage, where . The queue order from breadth-first search already supplies the layer order; no sorting or priority queue is needed. This improves the usual binary-heap Dijkstra bound and is linear in the input size.
Take the directed graph with source and weighted edges
It is a directed acyclic graph, so has no negative-weight graph cycle. The true shortest path to is , of weight .
The standard label-setting shortest-path algorithm version of the Dijkstra algorithm extracts , then at distance , then at distance , and only then at distance . Thus it finalises instead of . Even if an implementation subsequently changes the stored label of the already settled vertex , it does not reprocess its outgoing edge to , so the error at remains. Allowing repeated reprocessing would instead be a label-correcting shortest-path algorithm, not the usual Dijkstra guarantee.

Pinned article: Introduction to the OurBigBook Project

Welcome to the OurBigBook Project! Our goal is to create the perfect publishing platform for STEM subjects, and get university-level students to write the best free STEM tutorials ever.
Everyone is welcome to create an account and play with the site: ourbigbook.com/go/register. We belive that students themselves can write amazing tutorials, but teachers are welcome too. You can write about anything you want, it doesn't have to be STEM or even educational. Silly test content is very welcome and you won't be penalized in any way. Just keep it legal!
We have two killer features:
  1. topics: topics group articles by different users with the same title, e.g. here is the topic for the "Fundamental Theorem of Calculus" ourbigbook.com/go/topic/fundamental-theorem-of-calculus
    Articles of different users are sorted by upvote within each article page. This feature is a bit like:
    • a Wikipedia where each user can have their own version of each article
    • a Q&A website like Stack Overflow, where multiple people can give their views on a given topic, and the best ones are sorted by upvote. Except you don't need to wait for someone to ask first, and any topic goes, no matter how narrow or broad
    This feature makes it possible for readers to find better explanations of any topic created by other writers. And it allows writers to create an explanation in a place that readers might actually find it.
    Figure 1.
    Screenshot of the "Derivative" topic page
    . View it live at: ourbigbook.com/go/topic/derivative
  2. local editing: you can store all your personal knowledge base content locally in a plaintext markup format that can be edited locally and published either:
    This way you can be sure that even if OurBigBook.com were to go down one day (which we have no plans to do as it is quite cheap to host!), your content will still be perfectly readable as a static site.
    Figure 5. . You can also edit articles on the Web editor without installing anything locally.
    Video 3.
    Edit locally and publish demo
    . Source. This shows editing OurBigBook Markup and publishing it using the Visual Studio Code extension.
  3. https://raw.githubusercontent.com/ourbigbook/ourbigbook-media/master/feature/x/hilbert-space-arrow.png
  4. Infinitely deep tables of contents:
    Figure 6.
    Dynamic article tree with infinitely deep table of contents
    .
    Descendant pages can also show up as toplevel e.g.: ourbigbook.com/cirosantilli/chordate-subclade
All our software is open source and hosted at: github.com/ourbigbook/ourbigbook
Further documentation can be found at: docs.ourbigbook.com
Feel free to reach our to us for any help or suggestions: docs.ourbigbook.com/#contact