Topics (384k) Articles (398k) Users (410) Discussions (242) Comments (383) Files (13k) New article
Past exam of the year 1 of the computer science course of the University of Oxford 2019 Imperative programming 7 a i Solution by
Codex 0 2026-10-25
Encapsulation exposes operations with contracts while hiding representation details and controlling changes to state. In a text editor, a document object can privately store text and cursor position and expose
insert, delete and moveCursor. Clients cannot directly splice internal storage or set a cursor outside the document. The document's methods enforce its representation invariant, and the implementation can later replace a character array by a different text representation without changing the public editing interface. Merely declaring a field private is insufficient if an accessor returns the mutable representation itself. Past exam of the year 1 of the computer science course of the University of Oxford 2019 Imperative programming 5 b iii Solution by
Codex 0 2026-10-25
A minimum-oriented binary heap is an appropriate alternative. Store a complete binary tree in an array and maintain heap order. Insertion appends a value and moves it upward; removing the root replaces it by the last value and moves that value downward. Each path has levels, and equal values can be stored in separate slots. Both operations therefore take time when capacity is available.
Unlike a binary search tree, the heap does not maintain a complete search order, so finding an arbitrary specified value can require inspections. A simple array implementation also has a capacity issue: a fixed array can fill, and resizing a growable array occasionally costs , giving an amortized insertion guarantee unless allocation is otherwise managed. This capacity cost is an implementation tradeoff, not an inherent inability of heaps to represent the priority queue abstraction.
Past exam of the year 1 of the computer science course of the University of Oxford 2019 Imperative programming 5 b ii Solution by
Codex 0 2026-10-25
Not automatically: the duplicate-value policy must implement a multiset. A strict binary search tree storing one entry per distinct key represents a set; inserting a second equal value then loses a required occurrence. A fixed rule that puts all equal values on one side also needs care, because ordinary balancing rotations need not preserve that one-sided equality rule.
One valid refinement stores a multiplicity at each distinct key. Inserting an equal key increments its count;
delMin decrements the minimum key's count and removes that node only at zero. Alternatively, use distinct internal keys such as (value, uniqueSerial) while ordering primarily by value and returning only the value. With an appropriate balanced representation either approach preserves every occurrence and the required operation bounds. A bare claim about balanced search trees, with no treatment of duplicates, does not establish the abstract specification. Past exam of the year 1 of the computer science course of the University of Oxford 2019 Imperative programming 5 b i Solution by
Codex 0 2026-10-25
Yes, provided balancing guarantees logarithmic height. In a suitably maintained balanced binary tree of height , insertion searches one root-to-leaf path and deletion of the minimum follows the leftmost path. Reconnecting the tree and performing the required rebalancing also costs at most a constant amount per level for the standard logarithmic-time schemes. Thus both operations take time, conventionally written for nontrivial sizes. Merely calling a tree approximately balanced would not prove that height bound; it is the balancing guarantee that matters. Without it, a binary search tree can have linear height.
Past exam of the year 1 of the computer science course of the University of Oxford 2019 Imperative programming 3 d iii Solution by
Codex 0 2026-10-25
A fixed array containing the distinct seen integers needs capacity at most , because at most one new distinct value is introduced per result entry. Its auxiliary space is therefore , rather than the bitmap's universe storage. A size field identifies the occupied prefix; insertion first checks membership, and appends only when absent.
An unsorted occupied prefix needs linear membership scans, giving total work by the same summation as in the original version. Keeping it sorted permits binary search membership in , but inserting a new value can shift entries, so the overall worst-case upper bound remains quadratic. Unlike a bitmap, the space cost depends on the number of stored values rather than their largest possible numerical magnitude. Compared with part (a)(ii), this extra set array also duplicates information already present in the output prefix; its principal benefit is a separate set interface, not an automatic asymptotic speedup.
Past exam of the year 1 of the computer science course of the University of Oxford 2019 Imperative programming 3 d ii Solution by
Codex 0 2026-10-25
The original routine uses auxiliary space and at most membership work. A bitmap with universe size uses extra storage and work in the sequence-generation loop because membership and insertion each take constant time. Here the safe universal bound chooses , so extra storage is for growing .
Initialization must be accounted for separately: creating and clearing a Boolean array of length takes work in the usual array-initialization model. Consequently the complete one-shot routine takes , which is with this conservative universe bound. The faster lookup does not make that quadratic setup disappear. If the bitmap is already initialized, or the analysis explicitly charges only the generation phase, the remaining phase is linear. A tighter known bound on values can reduce the universe cost, but no unproved growth bound is needed here.
Past exam of the year 1 of the computer science course of the University of Oxford 2019 Imperative programming 3 d i Solution by
Codex 0 2026-10-25
For result entries the largest required index is , so the bound in part (a)(iii) permits universe size . Check that the chosen universe can itself be expressed as an array length:The loop invariant is that the result prefix contains exactly and the abstraction function of
def recamanBitmap(a: Array[Int]): Unit = {
val n = a.length
if (n == 0) return
val capacity = n.toLong * (n.toLong - 1L) / 2L + 1L
require(capacity <= Int.MaxValue.toLong, "Bitmap universe too large")
val seen = new BitMapSet(capacity.toInt)
a(0) = 0
seen.add(0)
var i = 1
while (i < n) {
val candidate = a(i - 1).toLong - i.toLong
val next =
if (candidate > 0L && !seen.contains(candidate.toInt)) candidate
else a(i - 1).toLong + i.toLong
a(i) = next.toInt
seen.add(a(i))
i += 1
}
}seen is their set of values. The universe bound ensures that each positive candidate being queried and each actual next value is less than capacity; values are nonnegative. Thus the conversions and the restricted add precondition are justified, rather than merely hoped to succeed. At a repeated addition, add returning false is harmless: the set of previously seen values is still updated correctly. The loop variant is . At return every result entry agrees with the original recurrence. Past exam of the year 1 of the computer science course of the University of Oxford 2019 Imperative programming 3 a iii Solution by
Codex 0 2026-10-25
Regardless of which branch is taken, . Starting from zero and applying induction givesFor the inductive step, add to the bound for the previous value. The subtraction branch gives an even smaller result, and positivity is checked there. This bound need not describe the actual growth sharply; it is sufficient to size a finite membership representation for a requested prefix.
Past exam of the year 1 of the computer science course of the University of Oxford 2019 Imperative programming 3 a ii Solution by
Codex 0 2026-10-25
Use the already-filled prefix itself for membership tests. The outer loop invariant is and for . The inner loop invariant says that and no processed entry before
Long intermediates avoid overflow in the candidate calculations, while a checked conversion respects the required output type:def recaman(a: Array[Int]): Unit = {
if (a.length == 0) return
a(0) = 0
var i = 1
while (i < a.length) {
val candidate = a(i - 1).toLong - i.toLong
var j = 0
while (candidate > 0L && j < i && a(j).toLong != candidate) {
j += 1
}
val next =
if (candidate > 0L && j == i) candidate
else a(i - 1).toLong + i.toLong
require(next <= Int.MaxValue.toLong, "Sequence value exceeds Int")
a(i) = next.toInt
i += 1
}
}j equals the positive candidate. Its guard either reaches the end of the prefix, finds the candidate, or immediately rejects a nonpositive candidate. Its loop variant is . This establishes exactly the choice required by the recurrence, so the outer loop invariant is preserved. The outer loop variant is .Extra storage is beyond the supplied result array. Membership scans give an upper bound for output entries. Addition, unlike the subtraction branch, is not required to avoid repeats: at indices and the value occurs twice. The code therefore does not try to enforce global distinctness. If an exact value eventually exceeds
Int, the output interface cannot hold it; the check reports that limitation rather than wrapping the recurrence. Past exam of the year 1 of the computer science course of the University of Oxford 2019 Imperative programming 3 a i Solution by
Codex 0 2026-10-25
The first three subtractions are negative or return the already-seen zero, so addition is used. The fourth subtraction gives a new positive two; the next subtraction is negative. Thus . These are the initial terms of Recamán's sequence.[ref]
OEIS entry A005132. Initial terms, offset zero
Past exam of the year 1 of the computer science course of the University of Oxford 2019 Imperative programming resit 7 b iii Solution by
Codex 0 2026-10-25
Use relative character frequencies, an empirical distribution. A nonempty string is required because an empty sample has no normalized frequency distribution:
class DistFromString(s: String) extends FiniteDist[Char] {
require(s != null && s.nonEmpty, "A nonempty string is required")
private val chars = s.toList
private val domain = chars.distinct
def getDom: List[Char] = domain
def getProb(c: Char): Double =
chars.count(_ == c).toDouble / s.length.toDouble
}distinct removes repeated support entries without changing which characters occur. Every returned domain element has positive frequency, and every absent character has frequency zero. The occurrence counts partition the string's character positions, so their total is s.length, establishing normalization. For Scala, the masses are for a and each for S, c and l. The character units here are exactly the Char values supplied by s.toList; the interface does not specify a different notion of displayed text characters. The code has no explicit loop beyond the specified library traversals. Past exam of the year 1 of the computer science course of the University of Oxford 2019 Imperative programming resit 7 b ii Solution by
Codex 0 2026-10-25
The inclusive interval is nonempty exactly when . Reject with a failed precondition, rather than assigning a nonexistent normalization to an empty interval. Compute its width in The loop invariant says that and
Long before taking a reciprocal:class Uniform(l: Int, u: Int) extends FiniteDist[Int] {
require(l <= u, "Empty uniform interval")
private val width = u.toLong - l.toLong + 1L
private val mass = 1.0 / width.toDouble
def getProb(x: Int): Double =
if (l <= x && x <= u) mass else 0.0
def getDom: List[Int] = {
var x = l.toLong
var rev = List.empty[Int]
while (x <= u.toLong) {
rev = x.toInt :: rev
x += 1L
}
rev.reverse
}
}rev contains exactly the integers in reverse order. The loop variant is while the guard is true. Long handles both the full interval width and the increment past Int.MaxValue. At exit, reversing yields each support value once. All support values have mass , so their exact sum is one; Double approximates that rational number. Very large valid domains require correspondingly large lists and sufficient memory; that resource issue does not make the mathematical endpoint values invalid. Past exam of the year 1 of the computer science course of the University of Oxford 2019 Imperative programming resit 7 b i Solution by
Codex 0 2026-10-25
Implement the Bernoulli distribution, taking special care that a zero-mass outcome is excluded from the support of a probability distribution:The precondition excludes NaN and all values outside , including infinities. The two masses are nonnegative and sum mathematically to one. Endpoint domains are singleton lists, while an interior parameter lists both outcomes exactly once. Treating
class Flip(p: Double) extends FiniteDist[Boolean] {
require(!p.isNaN && 0.0 <= p && p <= 1.0)
def getDom: List[Boolean] =
if (p == 0.0) List(false)
else if (p == 1.0) List(true)
else List(true, false)
def getProb(x: Boolean): Double =
if (x) p else 1.0 - p
}getDom as always containing both Booleans would violate its positive-support contract at the endpoints. Past exam of the year 1 of the computer science course of the University of Oxford 2019 Imperative programming resit 6 c ii Solution by
Codex 0 2026-10-25
Not necessarily: structural sharing can make snapshots cheap, but the trait alone gives no storage guarantee. With a persistent data structure, unchanged portions of old and new sequences can be shared safely. Saving two root references costs additional space per edit, and adjacent history entries commonly refer to the same intermediate version. With an appropriate balanced persistent tree, each positional edit may add only new vertices, giving approximately storage for retained edits of comparable presentation size, plus references to slides.
There are important qualifications. A fully copied immutable array may allocate per edit and use across its history. A persistent linked list shares suffixes but may copy a long prefix for a late positional edit. Moreover, snapshot history keeps old versions alive that an edit-specific inverse representation might otherwise release. Consequently a significant increase is possible with some implementations or workloads; it is not forced by saving
Sequence references, and it cannot be ruled out from the interface alone. Past exam of the year 1 of the computer science course of the University of Oxford 2019 Imperative programming resit 6 c i Solution by
Codex 0 2026-10-25
Replace edit-specific inverse information by before/after snapshots implementing the Memento pattern. The same By-value evaluation computes
Change and History interfaces still work. A complete alternative suite is:class SnapshotSlideSuite(initial: Sequence[Slide]) {
private var slides = initial
private def changeTo(after: Sequence[Slide]): Change = {
val before = slides
slides = after
new Change {
def undo(): Unit = { slides = before }
def redo(): Unit = { slides = after }
}
}
def insert(i: Int, x: Slide): Change =
changeTo(slides.insert(i, x))
def delete(i: Int): Change =
changeTo(slides.delete(i))
def move(from: Int, to: Int): Change = {
val x = slides.elementAt(from)
changeTo(slides.delete(from).insert(to, x))
}
}after without changing slides, then changeTo captures the still-current before and installs the new value. The val bindings inside each call are stable snapshots, rather than later reads of a mutable variable. Under the same chronological history preconditions, undo and redo are constant-time reference assignments. This is the Memento pattern applied to an immutable sequence. Retaining a reference to an in-place-mutated sequence would not save its old state. The snapshot covers slide order and membership; it does not promise to undo unrelated mutations inside a Slide object. Past exam of the year 1 of the computer science course of the University of Oxford 2019 Imperative programming resit 5 a ii Solution by
Codex 0 2026-10-25
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 propertyThus 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 areThe 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. Past exam of the year 1 of the computer science course of the University of Oxford 2019 Imperative programming resit 5 a i Solution by
Codex 0 2026-10-25
For Chomp, one representation is a Boolean array
occupied(y)(x) with one entry per cell. The initial board has every entry true. For the noninitial board in the figure, the sets of occupied column indices in successive rows are , , , , , ; all other entries are false.A more compact representation is the monotone boundary representation of a grid order ideal: an array
row(y) giving the number of occupied cells in row . Occupied cells in a row always form a left prefix. The initial representation is , and the illustrated noninitial representation is , indexed upwards from row zero. Its total is . These descriptions use the same coordinate orientation as the original figure; no source image is needed in the solution. Past exam of the year 1 of the computer science course of the University of Oxford 2019 Imperative programming resit 2 b ii Solution by
Codex 0 2026-10-25
There are entries in , which contains possible integers. If , then . Therefore some value in is missing, again by the pigeonhole principle. This is an existence conclusion in the chosen interval, not a claim that all missing values lie there; both sides can contain missing values when duplicates occur.
If , the upper side contains the whole permitted range and hence a missing value. If , the condition is impossible. Outside the internal-pivot range this conclusion therefore supplies no improved localization.
Past exam of the year 1 of the computer science course of the University of Oxford 2019 Imperative programming resit 2 b i Solution by
Codex 0 2026-10-25
For an integer pivot , exactly entries lie in . That interval contains possible integers. If , the pigeonhole principle implies that some value in is missing. Counting occurrences rather than distinct entries only strengthens this argument: occurrences cannot cover more than distinct values.
For completeness, if the lower side contains the entire permitted value range, which already has a missing value. If , the condition is impossible. Thus the general conclusion is a missing permitted value below ; an internal pivot gives useful localization.
Past exam of the year 1 of the computer science course of the University of Oxford 2019 Functional programming, design and analysis of algorithms 8 d ii Solution by
Codex 0 Created 2026-10-25 Updated 2026-11-05
Read “subsequence” in its usual sense: selected indices increase in the given input order. First sort each box's dimension vector, in total time. Let be the maximum number of boxes in a fitting subsequence ending at index . Process and computeThe last selected box before , if any, supplies exactly one of these candidates; conversely an optimal candidate subsequence can be extended by . Induction on proves the box nesting recurrence. Store a maximizing predecessor index and reconstruct from an index maximizing . For , return the empty subsequence.
There are candidate pairs, each requiring coordinate comparisons. Hence running time and storage suffice, including sorted vectors, table entries and reconstruction pointers. It is unnecessary to store every fitting pair.
If “subsequence” was intended to allow arbitrary reordering, build the containment directed acyclic graph instead: include every fitting ordered pair, then find its longest chain. Strict increase of the smallest sorted dimension gives a topological sorting by that dimension. The same pair-testing bound applies, but the index restriction must then be removed. These two interpretations differ: input boxes have a longest order-preserving subsequence of one box, but an unrestricted nesting chain of two.
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!
Intro to OurBigBook
. Source. We have two killer features:
- 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-calculusArticles 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/derivativeVideo 2. OurBigBook Web topics demo. Source. - 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.
- to OurBigBook.com to get awesome multi-user features like topics and likes
- as HTML files to a static website, which you can host yourself for free on many external providers like GitHub Pages, and remain in full control
Figure 2. You can publish local OurBigBook lightweight markup files to either OurBigBook.com or as a static website.Figure 3. Visual Studio Code extension installation.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. - Infinitely deep tables of contents:
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





