Source release: Oxford examination archive, member 2018/T/a10097w1.pdf. The cover dates this paper to 18 June 2019; the archive member's directory is misleading. The solutions cover every option. In the code, different definitions offered in different parts are alternatives, and the Haskell Prelude operations have their usual meanings unless redefined locally.
The right fold replaces the two list constructors by its two arguments; the left fold instead updates an accumulator while traversing the list.
foldr :: (a -> b -> b) -> b -> [a] -> b
foldr c z []     = z
foldr c z (x:xs) = c x (foldr c z xs)

foldl :: (b -> a -> b) -> b -> [a] -> b
foldl s a []     = a
foldl s a (x:xs) = foldl s (s a x) xs
Thus foldr is the natural list fold: it preserves the constructor arrangement while replacing [] by z and (:) by c. In particular, foldr (:) [] = id. More generally, the fold factorisation criterion says that the defining equations characterize the corresponding structural recursion. Association and lazy evaluation are separate: the accumulator in this definition of left fold is not automatically evaluated at each step.[ref]
For every accumulator , pattern matching makes foldl s a undefined the bottom value. Now use structural induction on a finite list prefix ending in the bottom value. The induction step is foldl s a (x:ps) = foldl s (s a x) ps; the induction hypothesis applies to every accumulator, including s a x. Consequently every such finite approximation has result .
An infinite lazy list is the limit of its finite prefixes, each interpreted as a finite approximation of a lazy list. Definable Haskell operations are Scott continuous maps, so the result on the infinite lazy list is the supremum of the results on these approximations. Every result is , hence foldl s a xs = undefined on every infinite input spine, irrespective of whether s would inspect the accumulator.
For a concrete separation, choose s = (&&), a = True, and xs = False : repeat True. The left fold is , whereas the right fold returns False after observing the first element: False && r does not demand r. It is reaching the end of the input spine, rather than strictness of the combining operation, that prevents this left fold from returning.
Over integers, choose s = c = (+) and a = b = 0. The left fold and right fold both compute the sum of a finite list.
Over integers, choose s = (-), c = flip (-), and a = b = 0. The left fold and right fold both compute the negative of the sum of a finite list. The combining functions differ: s 1 2 = -1, whereas c 1 2 = 1.
Let , using the specified operation . Direct evaluation gives , , , and .
Suppose with the same integer result type. The empty list forces . The two singleton calculations force and . But then
contrary to . No such c,b exist. This is the information restriction in the fold factorisation criterion: equal folded tails must remain indistinguishable after the same head is attached. A larger, function-valued result type can retain the missing information, as the continuation representation of a left fold does below.
Assign and . The application s y x forces for a fresh type ; applying f to that result forces . No further equations identify these four type variables. The principal type is therefore
k :: (u -> v -> w) -> v -> (w -> r) -> u -> r
k s x f y = f (s y x)
Every compatible typing is an instance of this one, because type inference imposed precisely the two application constraints and no class constraints.
Fix s and put . The right fold equations give
These are exactly the left fold equations. Structural induction, with the induction hypothesis quantified over all accumulators, proves equality on finite terminating lists.
To include the other input spines, first observe that both applied expressions give on an undefined spine. The same induction proves equality on every finite prefix ending in : the step k s x f a demands the continuation f when its result is demanded. Finally use that the two applied operations are Scott continuous maps, taking the limit over prefixes interpreted as a finite approximation of a lazy list. This covers infinite spines, on which both applied expressions are , and proves the identity for all lists under the stated Haskell semantics. The intermediate right fold builds an accumulator-transforming function; it does not provide a terminating left fold of an infinite list.
Include nonpositive counts and exhausted input explicitly:
take :: Int -> [a] -> [a]
take n _      | n <= 0 = []
take _ []             = []
take n (x:xs)         = x : take (n-1) xs

drop :: Int -> [a] -> [a]
drop n xs     | n <= 0 = xs
drop _ []             = []
drop n (_:xs)         = drop (n-1) xs
The tests on the count precede inspection of the input list. Thus take 0 undefined = [], while drop 0 undefined = undefined, exactly as these list prefix and list suffix operations require. No element value is inspected merely to traverse the spine.[ref]
A shared recursion computes both components:
split :: Int -> [a] -> ([a],[a])
split n xs | n <= 0 = ([],xs)
split _ []         = ([],[])
split n (x:xs)     = (x:ys,zs)
  where (ys,zs) = split (n-1) xs
For a defined count and a spine with available constructors before termination, each of take and drop makes recursive calls, whereas split makes that many once. The number of recursive calls is halved. The irrefutable pattern in the local pair binding also avoids evaluating the recursive pair merely to expose the first output element.
On proper lazy lists this has the intended two component values. There is a small bottom value distinction outside that domain: the displayed single-pass definition must inspect a positive-count input spine before returning its outer pair, whereas the literal expression (take n xs, drop n xs) exposes the pair constructor even if xs is undefined. The algorithmic answer concerns the two components and the stated call count; it need not silently claim equality under a test that observes this outer constructor alone.
For the paper's leaf-labelled binary tree, the combining operation receives the results of the two subtrees, and the other argument handles a leaf:
foldTree :: (a -> b) -> (b -> b -> b) -> Tree a -> b
foldTree f g (One x)   = f x
foldTree f g (Two l r) = g (foldTree f g l) (foldTree f g r)
Its constructor equation is foldTree One Two = id. More generally, a function h satisfying h (One x) = f x and h (Two l r) = g (h l) (h r) equals foldTree f g on finite trees, by structural induction. This is the tree fold specialized to a datatype with labels only at leaves, rather than at internal nodes.
Both versions preserve left-to-right leaf order:
flatten :: Tree a -> [a]
flatten (One x)   = [x]
flatten (Two l r) = flatten l ++ flatten r

flattenFold :: Tree a -> [a]
flattenFold = foldTree (\x -> [x]) (++)
The tree fold replaces each leaf by a singleton list and each internal node by list concatenation. The defining equations of flattenFold are consequently those of flatten, proving their equality by structural induction.
Let be the number of leaves; the total number of nodes is . List concatenation copies its left operand. For a tree whose left subtree contains leaves at each successive internal node, these copied lengths are . Their sum is , so the worst-case running time is .
A difference list representation avoids copying prefixes:
flattenFast :: Tree a -> [a]
flattenFast t = go t []
  where
    go (One x)   acc = x:acc
    go (Two l r) acc = go l (go r acc)
The recursion invariant is go t acc = flatten t ++ acc. The leaf case is immediate; the internal-node case uses associativity of list concatenation. Each node is visited once and each leaf contributes one output constructor, giving running time when the result is fully consumed. This is linear flattening of a binary tree and does not assume balance.
The necessary domain is a finite, nonempty list: the datatype has no representation of an empty leaf sequence, and the supplied size-based balance condition does not specify an infinite-size construction.
build :: [a] -> Tree a
build []  = error "build: empty input"
build [x] = One x
build xs  = Two (build ys) (build zs)
  where
    (ys,zs) = split (length xs `div` 2) xs
For length , the two nonempty pieces have and elements. Their sizes differ by at most one, and both are shorter than the input. Induction therefore proves termination and the required leaf-balanced binary tree property at every node. The same induction, using ys ++ zs = xs, proves flatten (build xs) = xs. This straightforward implementation takes running time; computing the length repeatedly is acceptable here because no faster construction was requested.
Use the input list as the seed of the tree unfold:
buildUnfold :: [a] -> Tree a
buildUnfold = unfold step
  where
    step []  = error "build: empty input"
    step [x] = Left x
    step xs  = Right (split (length xs `div` 2) xs)
On a singleton seed, unfold produces the same leaf as build; on a longer finite seed, it recursively builds the same two pieces. Induction on input length proves buildUnfold = build on finite nonempty inputs. The empty-input qualification remains essential: a tree unfold cannot supply a missing empty-tree constructor.
Use coordinates with row and column in :
type Place  = (Int,Int)
type Places = [Place]
type Board  = (Places,Places,Places)
data Player = O | X deriving (Eq,Ord,Show)
The components of Board record the positions occupied by O, occupied by X, and still empty, respectively. On a nonterminal legal board, equal occupied counts mean O moves next; one extra O means X moves next.
The type synonym does not enforce the representation invariant: coordinates are in range; each component has no duplicates; the three represented sets form a set partition of the nine positions; and the occupied counts differ as just described. Both players cannot have won. A winning O board has one extra O, and a winning X board has equal counts. More fundamentally, a legal tic-tac-toe state has a legal alternating history that stops at the first win: satisfying a type alone never licenses continuing an already completed game.
The empty occupancy sets leave all nine coordinates available:
empty :: Board
empty = ([],[],[(r,c) | r <- [0..2], c <- [0..2]])
This board satisfies the representation invariant and gives O the next move.
Assume the board satisfies the representation invariant. Reject completed boards and occupied or out-of-range coordinates; testing membership in the empty component covers both coordinate failures.
finished :: Board -> Bool
finished (os,xs,es) = won os || won xs || null es

play :: Board -> Place -> Board
play b@(os,xs,es) q
  | finished b     = error "play: completed game"
  | q `notElem` es = error "play: unavailable place"
  | length os == length xs = (q:os,xs,rest)
  | otherwise             = (os,q:xs,rest)
  where rest = filter (/=q) es
Here won is defined in part d. Moving one available coordinate into the appropriate occupied component preserves the set partition and the alternating-count rule. Checking completion first preserves the no-moves-after-a-win invariant.
Construct each possible winning line, then test whether one is contained in the player's occupancy set:
winningLines :: [Places]
winningLines =
  [[(r,c) | c <- [0..2]] | r <- [0..2]] ++
  [[(r,c) | r <- [0..2]] | c <- [0..2]] ++
  [[(i,i) | i <- [0..2]], [(i,2-i) | i <- [0..2]]]

won :: Places -> Bool
won ps = any (\line -> all (`elem` ps) line) winningLines
The list comprehension generates three rows, three columns and two diagonals. Each has exactly three coordinates; therefore all holds precisely when every coordinate of that line is occupied by this player. Taking any over the eight lines proves the win test correct.
Record the outcome at the first completed board and otherwise branch over every available move:
data Outcome = Winner Player | Draw deriving (Eq,Ord,Show)

finals :: Board -> [(Board,Outcome)]
finals b@(os,xs,es)
  | won os    = [(b,Winner O)]
  | won xs    = [(b,Winner X)]
  | null es   = [(b,Draw)]
  | otherwise = concatMap (\q -> finals (play b q)) es
The recursion terminates because each recursive call decreases the number of empty positions by one. For correctness, induct on that number. A completed board contributes exactly its own outcome. Otherwise every legal continuation has a unique first available move, and the induction hypothesis covers exactly all completions after that move. List concatenation collects these branches without extending completed games. Repeated final positions are allowed here because the computation deliberately explores every legal move sequence.
Different move orders can lead to the same position, and the two occupancy lists also retain irrelevant insertion order. Thus this search tree repeatedly solves the same remaining game. For example, swapping the order of two O moves while leaving the intervening X moves legal can reach the same occupied sets.
Canonicalize each state by sorted occupancy sets, or by two bitboards, and apply memoization or a visited-state set. Expand each canonical position once, stopping at terminal states, and collect terminal positions in a set. There are at most cell assignments, many of which are illegal; this is much smaller than a tree of move permutations. Store positions, not histories, when the requested output is distinct final positions. Board rotations and reflections can reduce work further if handled as an additional equivalence: if the output must retain every oriented board, reconstruct those distinct orientations rather than silently returning one representative per symmetry class.
For proper lazy lists, the generic condition is a finite first list, or an empty second list. A finite first list reaches its terminating constructor, after which list concatenation exposes the second one. An infinite first list never yields control to the second; it therefore cannot deliver occurrences originating there unless there are none. This concerns input occurrences, rather than an accidental overlap of the two inputs' value sets.
A first spine ending in the bottom value also prevents access to the second list. Such inputs require the partial-input qualification in part c; a visible prefix is different from a terminating finite list.
Swap roles after emitting one element:
interleave :: [a] -> [a] -> [a]
interleave []     ys = ys
interleave (x:xs) ys = x : interleave ys xs
While both lists are nonempty, the function alternates between them. Their -th input occurrences appear after at most output steps, counting positions from zero; once either list ends, the other is returned directly. Every output constructor comes from one input constructor, and every input occurrence is eventually selected. This proves fair enumeration and productivity on the two proper lazy lists, including two infinite ones.
No universally correct sequential Haskell implementation has that guarantee for partial lists. Compare undefined paired with [v], and [v] paired with undefined, where the element type is arbitrary. A generic program cannot fabricate v; it must eventually inspect an input spine to obtain it. Whichever input it first demands can be chosen to be the undefined one, blocking access to the available element in the other input.
In particular, the implementation in part b can emit a defined prefix and then block when alternation reaches an undefined tail. Lazy evaluation postpones demands; it cannot recognize that a demanded computation will never finish. The result is the partial-list interleaving obstruction, not an objection to fairness under the proper-input hypothesis. Additional concurrent primitives would change the computational model.[ref]
Use diagonal merging of lazy lists: introduce one new row each round, and advance every active row once. Each round contains finitely many active rows, even when the outer list is infinite.
fairConcat :: [[a]] -> [a]
fairConcat = concat . levels []
  where
    levels [] [] = []
    levels active pending =
      let (new,rest) = case pending of
            []     -> ([],[])
            r:rs   -> ([r],rs)
          live = [r | r@(_:_) <- active ++ new]
      in map head live : levels (map tail live) rest
Number rows and positions within each row from zero. An occurrence at is emitted in round : its row enters in round and advances once per subsequent round. All earlier rounds and each round's output are finite, so every required occurrence appears after finite work. live discards only empty rows, and head emits only existing entries; no new value is invented.
Figure 1.
Diagonal merging of lazy lists visits every finite row-position pair after finitely many rounds
. Details.
Simply nesting interleave is unsafe here: foldr interleave [] ([1,2] : repeat []) emits 1 and then demands an undefined merge of the infinitely many empty rows before it can emit 2. The finite-round construction avoids that starvation. There is still an unavoidable termination qualification: after the last actual output, infinitely many empty pending rows cannot be certified empty in finite work. The result can then have an undefined tail instead of a terminating []. Every required occurrence has nevertheless appeared; no generic algorithm can promise a proper completed output in that exceptional situation, by the absence-detection obstruction for infinite lists.
The ordinary list comprehension exhausts the inner list before advancing the outer one. Therefore it enumerates every argument pair when ys is finite, or when xs has at most one element. If ys is infinite and xs has two or more elements, it stays with the first outer element forever and misses every pair with a later outer occurrence. Applying a constant f might hide missing pairs as duplicate values; it does not make the enumeration fair.
An empty-result caveat remains when ys = [] and xs is infinite: the literal comprehension traverses infinitely many empty rows and does not return a terminating empty list. Its occurrence requirement is vacuous, but its productivity as an empty-result computation fails. An explicit empty-input test avoids that particular failure.
Merge the rows with fairConcat, retaining explicit empty-input cases:
fairPair :: (a -> b -> c) -> [a] -> [b] -> [c]
fairPair _ [] _  = []
fairPair _ _  [] = []
fairPair f xs ys = fairConcat [[f x y | y <- ys] | x <- xs]
For nonempty proper lazy lists, the occurrence f (xs!!i) (ys!!j) belongs to row , position , so the proof in part d puts it in round . This supplies every pair after finite work, even when both input lists are infinite. The guards also return [] for either empty factor without traversing infinitely many empty rows.
For a finite outer list of proper lazy lists, use the fair binary product from part f:
cp :: [[a]] -> [[a]]
cp []       = [[]]
cp (xs:xss) = fairPair (:) xs (cp xss)
The empty family has one selection, the empty selection. For a nonempty finite family, each selection consists uniquely of one first-factor occurrence followed by a selection from the remaining factors. Induction on the number of factors, together with the fairness of fairPair, proves that every such selection is produced and no invalid selection is introduced. Infinite factors are allowed: in particular, the three-factor example is enumerated fairly. If any factor is empty, the finite-family computation returns the empty product.
The printed hypothesis also permits an infinite outer proper lazy list. No function can satisfy the full enumeration requirement for all such inputs. Take repeat [0,1]. Its mathematical Cartesian product contains every infinite binary sequence and is uncountable. If a result list enumerated these sequences as , the binary sequence with would differ from the -th listed sequence at position , contradicting completeness. This is an uncountability obstruction to enumerating infinite Cartesian products. The finite-outer qualification is a necessary repair to the specification, not a restriction imposed for convenience by the code.
A divide-and-conquer algorithm handles a small input directly; otherwise it divides the input into smaller instances, recursively solves them, and combines their answers. With equally sized subproblems of size approximately and nonrecursive work , its recurrence relation has the form , with constant-size base cases, and .
Write . The basic master theorem gives the following cases, with a fixed :
  • If , then .
  • If , then .
  • If and the regularity condition holds eventually for some , then .
For the common extended middle case, with fixed gives . A recursion tree explains the three cases: work is dominated by its leaves, spread across comparable levels, or dominated by its top levels. The regularity condition in the last case is part of the theorem, not an optional simplification.
For an ascending sorted array, maintain a candidate interval initially containing every index. Compare the target with the middle entry at . Equality returns ; if the target is smaller, replace by ; if larger, replace by . An empty interval reports absence.
The loop invariant is that any target occurrence still possible lies inside the candidate interval. Sortedness justifies discarding the appropriate half after each unequal comparison. The interval length decreases to at most half its previous length, establishing termination and correctness. After unsuccessful comparisons there are at most candidates, so at most comparisons suffice for . Each iteration uses constant work on a random-access array. Thus binary search takes running time, conventionally written for nontrivial input sizes. Empty input is handled in constant time.
Assume ascending sorted arrays; descending storage can be accessed in reverse index order without copying. Among entries, the requested rank is in ascending order, not . Repeated values occupy repeated ranks.
Choose entries from the first array and from the second, using their prefixes. The feasible range is . Write , , and similarly at , with missing left endpoints replaced by and missing right endpoints by . These are conceptual sentinels, not extra stored entries.
Use binary search over the feasible values of :
  • If , there are too many entries from on the left; decrease the upper bound to .
  • If , there are too few entries from on the left; increase the lower bound to .
  • Otherwise return .
For correctness, in the last case every left entry is no greater than every right entry, and exactly entries lie on the left. Their maximum is therefore the -th smallest entry. The failed inequalities are monotone in the searched index: increasing raises the boundary and decreases the boundary, so it cannot repair ; the other case is symmetric. A partition of the first entries of a merged ordering supplies an admissible solution, including ties. Each step halves an interval with at most choices, giving running time and auxiliary space. This is a two-sorted-array order statistic without constructing the merged array.
If coordinate is not an essential variable of a function, changing that coordinate alone never changes the output, for any values of the other coordinates. Take two inputs with the same -th coordinate. Change their other coordinates one at a time to transform the first input into the second. Every such change is inessential, so all intermediate outputs are equal.
Define , with in position . The preceding argument gives . Since is essential, is nonconstant. The conclusion depends on the full “for every context” negation of essentiality, not merely on testing a coordinate at one selected input.
If , return its sole index without a query. Otherwise first evaluate for until two different outputs are found. Part i says these outputs are precisely , so two values with must exist. This uses at most calls to the function-evaluation oracle.
Maintain a candidate index set , initially all indices. Split into two nearly equal pieces and choose one, . Query the input that is on and everywhere else. Its output equals exactly when , and otherwise equals . Retain the indicated half and repeat until one index remains.
The loop invariant is , and the witness outputs keep each test unambiguous. There are at most splitting queries. The total is at most evaluations, which is for , and in fact a stronger additive bound. Only oracle calls are being counted; explicitly constructing each query vector can require ordinary work. This is identification of a unique essential variable.
Restrict the unknown function to the possibilities if , and otherwise. Each has exactly one essential variable, even if the allowed alphabet has more than two values. Every oracle answer in this restricted family is one bit.
A correct adaptive deterministic algorithm must distinguish all possibilities. A binary decision tree of depth has at most leaves, so . Therefore . Restricting the answer family is essential to the argument: unrestricted integer-valued answers need not have binary branching. Combined with part ii, this gives optimal logarithmic query complexity for fixed .
Store a complete binary tree in a one-indexed array , level by level. Index has parent in a rooted tree for and possible children in a rooted tree and , present only when their indices are at most . The max-heap condition is for every .
Following these inequalities from the root of a tree to any entry proves that is a maximum. The heap order does not sort siblings or unrelated branches. The complete binary tree has height , which bounds how far any single repair can travel. Store the current heap size separately from the array's capacity.
Assume the subtrees rooted at the children in a rooted tree of already obey the max-heap condition. Compare with each present child and choose an index of the largest of these at most three keys. If that index is , stop. Otherwise exchange the two keys, continue at the chosen child, and repeat. This is sift down, with the inequality reversed from a minimum-oriented binary heap.
The exchange repairs the old root position because its new key dominates both child roots; only the subtree receiving the displaced key can still be defective. This recursion invariant proves correctness. Each exchange descends one level and costs constant work, so the worst-case running time is for subtree height , hence . A small key at the root of a suitably ordered heap must descend to a leaf, so the logarithmic worst-case bound is attained.
Leaves already obey the heap order. Process indices , calling the preceding repair at each. When an index is processed, its descendants have already been processed, so the repair's precondition holds. The resulting array is a max-heap.
The bound obtained by charging to every call is unnecessarily large. The number of nodes with height at least is at most . Therefore
The total repair work is thus , and the loop itself has a linear number of iterations, giving for this bottom-up heap construction. Most nodes are near the leaves and require little repair.
A maximum priority queue stores keyed entries and supports insertion, inspection and removal of an entry with greatest key, and key increases. A max-heap gives the following running times, with the size/capacity cost of the backing array accounted for separately:
Empty-queue inspections and removals need an explicit failure result. The index argument to increaseKey must identify the entry's current location: if callers use item handles, update their location records during swaps.
Given the target's current heap index , remove it as follows. If , discard the last entry. Otherwise replace by and reduce by one. If the replacement is larger than its parent in a rooted tree, use sift up; otherwise use the maximum-oriented sift down from .
Only comparisons incident to the replacement can initially violate the heap order. If it exceeds its parent, it also dominates the old children because the old key dominated those children and was no larger than the parent; an upward repair suffices. Otherwise the upward comparison is valid and only a downward repair can be needed. Thus removal takes worst-case time after the location is known. Searching an unindexed heap for an arbitrary specified key can instead require time; the logarithmic bound does not include such a search.
Only arrange switches towards A. For every vertex , compute its degree and the current number of neighbours preferring A. Put the B vertices in a max-heap with key . Maintain each vertex's current heap array index during exchanges.
While the queue is nonempty and its maximum key is positive, extract that vertex , show it its neighbours' preferences, append to the answer sequence, and set its preference to A. For every neighbour still preferring B, increase by one and use increaseKey to increase its heap key by two. Stop when every remaining key is nonpositive.
A positive key means precisely a strict majority of A neighbours, so every listed move is legal. Degrees never change; A neighbours never revert in this chosen sequence. An isolated B vertex has key zero and cannot be converted. Initialization costs , there are at most extractions, and each edge causes at most two neighbour inspections and at most a constant number of key updates. The required bound is therefore . A simple work queue of newly eligible vertices can even implement the same monotone threshold activation in time, since a vertex needs to be enqueued only once.
Let be the final A set produced by the algorithm. It contains the initial A set, and every vertex outside has at most half its neighbours in : otherwise its final key would still be positive. Thus is closed under the activation rule.
Now consider any legal sequence, including sequences which change some A preferences back to B. We prove by induction that its current A set is always a subset of . This is true initially. A switch to B preserves the inclusion. If a vertex outside were to switch to A, its A neighbours would all lie in , so their number could not exceed half its degree. Such a switch is forbidden. A switch inside also preserves the inclusion.
Consequently every attainable final A set has size at most . The algorithm supplies a legal sequence attaining itself, so its sequence is optimal. This closure dominance for asynchronous threshold switching proves more than a local-greedy claim: temporary losses of A vertices cannot unlock an additional vertex outside the activation closure.
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.
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.
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.
Let use only the first available coins. Initialize , for , and use
omitting the second term when . The alternatives exclude the current coin or use it once; both refer to the previous row, so it cannot be used twice. Induction on proves correctness, and is the required answer, including when no selection works.
The running time is . A single amount array reduces auxiliary space to if each coin updates amounts in descending order, . Then still describes the previous row. Ascending updates would reuse the same coin and solve a different, unlimited-supply problem.
Articles were limited to the first 100 out of 119 total.

Articles by others on the same topic (0)

There are currently no matching articles.