Where, however, the ambiguity cannot be cleared up, either by the rule of faith or by
the context, there is nothing to hinder us to point the sentence according to any
method we choose of those that suggest themselves.
— Augustine of Hippo, De doctrina Christiana (�����)Translated by Marcus Dods (�8��)I dropped my dinner, and ran back to the laboratory. There, in my excitement,
I tasted the contents of every beaker and evaporating dish on the table. Luckily forme, none contained any corrosive or poisonous liquid.
— Constantine Fahlberg on his discovery of saccharin,
Scienti�c American (�886)
The greatest challenge to any thinker is stating the problem
in a way that will allow a solution.
— attributed to Bertrand Russell
When you come to a fork in the road, take it.
— Yogi Berra (giving directions to his house)�Backtracking

This chapter describes another important recursive strategy called backtracking.
A backtracking algorithm tries to construct a solution to a computational problem
incrementally, one small piece at a time. Whenever the algorithm needs todecide between multiple alternatives to the next component of the solution, it
recursively evaluates every alternative and then chooses the best one.

�.�N Queens

The prototypical backtracking problem is the classical n Queens Problem, first
proposed by German chess enthusiast Max Bezzel in(under his pseudonym“Schachfreund”) for the standard 8 ⇥ 8 board and by François-Joseph Eustache
Lionnet infor the more general n ⇥ n board. The problem is to place nqueens on an n ⇥ n chessboard, so that no two queens are attacking each other.
���. B�����������

For readers not familiar with the rules of chess, this means that no two queens
are in the same row, the same column, or the same diagonal.

♕
♕
♛
♕
♕
♕
♛
♕
♕
♛
♕
♛
Figure �.�. Gauss’s �rst solution to the 8 queens problem, represented by the array [5, 7, 1, 4, 2, 8, 6, 3]

In a letter written to his friend Heinrich Schumacher in, the eminent
mathematician Carl Friedrich Gauss wrote that one could easily confirm Franz
Nauck’s claim that the Eight Queens problem has
solutions by trial anderror in a few hours. (“Schwer ist es übrigens nicht, durch ein methodisches
Tatonniren sich diese Gewissheit zu verschaffen, wenn man oder ein paar Stundendaran wenden will.”) His description Tatonniren comes from the French tâtonner,
meaning to feel, grope, or fumble around blindly, as if in the dark.
Gauss’s letter described the following recursive strategy for solving then-queens problem; the same strategy was described inby the French
recreational mathematician Édouard Lucas, who attributed the method to
Emmanuel Laquière. We place queens on the board one row at a time, startingwith the top row. To place the rth queen, we methodically try all n squares inrow r from left to right in a simple for loop. If a particular square is attacked byan earlier queen, we ignore that square; otherwise, we tentatively place a queen
on that square and recursively grope for consistent placements of the queens inlater rows.
Figure . shows the resulting algorithm, which recursively enumerates allcomplete n-queens solutions that are consistent with a given partial solution.
Following Gauss, we represent the positions of the queens using an arrayQ[1 .. n], where Q[i] indicates which square in row i contains a queen. WhenPQ
is called, the input parameter r is the index of the first empty row,and the prefix Q[1 .. r 1] contains the positions of the first r 1 queens. In
particular, to compute all n-queens solutions with no restrictions, we would call
P
Q
(Q[1 .. n], 1). The outer for-loop considers all possible placementsof a queen on row r; the inner for-loop checks whether a candidate placementof row r is consistent with the queens that are already on the first r 1 rows.
The execution of PQ
can be illustrated using a recursion tree.
Each node in this tree corresponds to a recursive subproblem, and thus to alegal partial solution; in particular, the root corresponds to the empty board���.�. N Queens

P

Q(Q[1 .. n], r):
if r = n + 1
print Q[1 .. n]
else
for j
1 to nlegal Tfor i
1 to r 1
if (Q[i] = j) or (Q[i] = j + r i) or (Q[i] = j r + i)
legal F
if legal
Q[r]jP
Q(Q[1 .. n], r + 1)
hhRecursion!ii

Figure �.�. Gauss and Laquière’s backtracking algorithm for the n queens problem.

(with r = 0). Edges in the recursion tree correspond to recursive calls. Leaves
correspond to partial solutions that cannot be further extended, either because
there is already a queen on every row, or because every position in the next
empty row is attacked by an existing queen. The backtracking search forcomplete solutions is equivalent to a depth-first search of this tree.

♕

♕

♕
♛

♕

♕

♕
♛

♕
♛

♕

♕

♕

♕

♕
♛

♕

♕
♛

♕
♛
♕
♛

♕
♛

♕
♛
♕

♕

♕
♕
♛

♕
♛

♕
♛
♕
♛

♕

♕
♛

♕
♛

♕

♕
♕

♕
♛

♕

♕
♛
♕
♛

♕

Figure �.�. The complete recursion tree of Gauss and Laquière’s algorithm for the � queens problem.

���. B�����������

�.�

Game Trees

Consider the following simple two-player game played on an n ⇥ n square gridwith a border of squares; let’s call the players Horace Fahlberg-Remsen andVera Rebaudi. Each player has n tokens that they move across the board fromone side to the other. Horace’s tokens start in the left border, one in each row,and move horizontally to the right; symmetrically, Vera’s tokens start in the
top border, one in each column, and move vertically downward. The players
alternate turns. In each of his turns, Horace either moves one of his tokens one
step to the right into an empty square, or jumps one of his tokens over exactly
one of Vera’s tokens into an empty square two steps to the right. If no legal
moves or jumps are available, Horace simply passes. Similarly, Vera either moves
or jumps one of her tokens downward in each of her turns, unless no moves or
jumps are possible. The first player to move all their tokens off the edge of theboard wins. (It’s not hard to prove that as long as there are tokens on the board,at least one player can legally move, and therefore someone eventually wins.)

Figure �.�. Vera wins the � ⇥ � fake-sugar-packet game.

I don’t know what this game is called, or even if I’m reporting the rules correctly; I learnedit (or something like it) from Lenny Pitt, who recommended playing it with fake-sugar packets at
restaurants.
Constantin Fahlberg and Ira Remsen synthesized saccharin for the first time in, whileFahlberg was a postdoc in Remsen’s lab investigating coal tar derivatives. In, Ovidio Rebaudi
published the first chemical analysis of ka’a he’ê, a medicinal plant cultivated by the Guaraní formore thanyears, now more commonly known as Stevia rebaudiana.

���.�. Game Trees

Unless you’ve seen this game before , you probably don’t have any idea how
to play it well. Nevertheless, there is a relatively simple backtracking algorithm
that can play this game—or any two-player game without randomness or hidden
information that ends after a finite number of moves—perfectly. That is, if wedrop you into the middle of a game, and it is possible to win against anotherperfect player, the algorithm will tell you how to win.
A state of the game consists of the locations of all the pieces and the identityof the current player. These states can be connected into a game tree, which has
an edge from state x to state y if and only if the current player in state x canlegally move to state y. The root of the game tree is the initial position of thegame, and every path from the root to a leaf is a complete game.

Figure �.�. The �rst two levels of the fake-sugar-packet game tree.

To navigate through this game tree, we recursively define a game state to
be good or bad as follows:• A game state is good if either the current player has already won, or if thecurrent player can move to a bad state for the opposing player.
• A game state is bad if either the current player has already lost, or if every
available move leads to a good state for the opposing player.
Equivalently, a non-leaf node in the game tree is good if it has at least one badchild, and a non-leaf node is bad if all its children are good. By induction, any
player that finds the game in a good state on their turn can win the game, even
if their opponent plays perfectly; on the other hand, starting from a bad state, aplayer can win only if their opponent makes a mistake. This recursive definition
was proposed by Ernst Zermelo in.
If you have, please tell me where!
In fact, Zermelo considered the more subtle class of games that have a finite number ofstates, but that allow infinite sequences of moves. (Zermelo defined infinite play to be a draw.)���. B�����������

This recursive definition immediately suggests the following recursive backtracking algorithm to determine whether a given game state is good or bad. At
its core, this algorithm is just a depth-first search of the game tree; equivalently,
the game tree is the recursion tree of the algorithm! A simple modification ofthis backtracking algorithm finds a good move (or even all possible good moves)
if the input is a good game state.
P

A G(X , player):if player has already won in state X
return G
if player has already lost in state X
return B
for all legal moves X † Y
if P A G(Y, ¬player) = B
return G
hhX † Y is a good moveii
return B
hhThere are no good movesii

All game-playing programs are ultimately based on this simple backtracking
strategy. However, since most games have an enormous number of states, it is
not possible to traverse the entire game tree in practice. Instead, game programs
employ other heuristics to prune the game tree, by ignoring states that are
obviously (or “obviously”) good or bad, or at least better or worse than otherstates, and/or by cutting off the tree at a certain depth (or ply) and using amore efficient heuristic to evaluate the leaves.

�.�

Subset Sum

Let’s consider a more complicated problem, called S
S : Given a set X
of positive integers and target integer T , is there a subset of elements in X that
add up to T ? Notice that there can be more than one such subset. For example,
if X = {8, 6, 7, 5, 3, 10, 9} and T = 15, the answer is T
, because the subsets{8, 7} and {7, 5, 3} and {6, 9} and {5, 10} all sum to 15. On the other hand, if
X = {11, 6, 5, 1, 7, 13, 12} and T = 15, the answer is F.
There are two trivial cases. If the target value T is zero, then we canimmediately return T, because the empty set is a subset of every set X , andthe elements of the empty set add up to zero. On the other hand, if T < 0, or
if T 6= 0 but the set X is empty, then we can immediately return F.
For the general case, consider an arbitrary element x 2 X . (We’ve alreadyhandled the case where X is empty.) There is a subset of X that sums to T if
and only if one of the following statements is true:
A heuristic is an algorithm that doesn’t work. (Except in practice. Sometimes. Maybe.). . . because what else could they add up to?

�6�.�. Subset Sum• There is a subset of X that includes x and whose sum is T .
• There is a subset of X that excludes x and whose sum is T .
In the first case, there must be a subset of X \ {x} that sums to T x; in thesecond case, there must be a subset of X \ {x} that sums to T . So we can solve
S
S (X , T ) by reducing it to two simpler instances: S
S (X \{x},T x) and S
S (X \ {x}, T ). The resulting recursive algorithm is shown
below.
hhDoes any subset of X sum to T ?ii
S
S (X , T ):if T = 0
return T
else if T < 0 or X = ?
return Felsexany element of X
withS
S (X \ {x}, T x)
wout SS (X \ {x}, T )return (with _ wout)

hhRecurse!ii
hhRecurse!ii

Correctness
Proving this algorithm correct is a straightforward exercise in induction. If
T = 0, then the elements of the empty subset sum to T , so T
is the correct
output. Otherwise, if T is negative or the set X is empty, then no subset of X
sums to T , so F
is the correct output. Otherwise, if there is a subset thatsums to T , then either it contains X [n] or it doesn’t, and the Recursion Fairy
correctly checks for each of those possibilities. Done.

Analysis
In order to analyze the algorithm, we have to describe a few implementation
details more precisely. To begin, let’s assume that the input set X is given as anarray X [1 .. n].
The previous recursive algorithm allows us to choose any element x 2 X in
the main recursive case. Purely for the sake of efficiency, it is helpful to choose
an element x such that the remaining subset X \ {x} has a concise description,
which can be computed quickly, so that setting up the recursive calls requires
minimal overhead. Specifically, we will let x be the last element X [n]; thenthe subset X \ {x} is stored in the prefix X [1 .. n 1]. Passing a complete copyof this prefix to the recursive calls would take too long—we need ⇥(n) time
just to make the copy—so instead, we push only two values: a reference to thearray (or its starting address) and the length of the prefix. (Alternatively, we���. B�����������

could avoid passing a reference to X to every recursive call by making X a global
variable.)
hhDoes any subset of X [1 .. i] sum to T ?ii
S
S (X , i, T ):if T = 0
return T
else if T < 0 or i = 0
return F
else
with
S
S (X , i 1, T X [i])wout SS (X , i 1, T )return (with _ wout)

hhRecurse!ii
hhRecurse!ii

With these implementation choices, the running time T (n) of our algorithm
satisfies the recurrence T (n)  2T (n 1) + O(1). The solution T (n) = O(2n )follows easily using either recursion trees or the even simpler “Oh yeah, wealready solved this recurrence for the Tower of Hanoi” method. In the worst
case—for example, when T is larger than the sum of all elements of X —therecursion tree for this algorithm is a complete binary tree with depth n, and thealgorithm considers all 2n subsets of X .

Variants
With only minor changes, we can solve several variants of S
S . Forexample, Figure . shows an algorithm that actually constructs a subset of X
that sums to T , if one exists, or returns the error value N
if no such subset
exists; this algorithm uses exactly the same recursive strategy as our earlier
decision algorithms. This algorithm also runs in O(2n ) time; the analysis issimplest if we assume a set data structure that allows us to insert a single
element in O(1) time (for example, a linked list), but in fact the running timeis still O(2n ) even if insertion requires O(n) time (for example, a sorted linkedlist). Similar variants allow us to count subsets that sum to a particular value,or choose the best subset (according to some other criterion) that sums to aparticular value.
Most other problems that are solved by backtracking have this property:
the same recursive strategy can be used to solve many different variants of thesame problem. For example, it is easy to modify the recursive strategy describedin the previous section, which determines whether a given game position isgood or bad, to instead return a good move, or a list of all good moves. For
this reason, when we design backtracking algorithms, we should aim for thesimplest possible variant of the problem, computing a number or even a single
boolean instead of more complex information or structure.
�8�.�. The General Pattern

hhReturn a subset of X [1 .. i] that sums to T ii
hhor N��� if no such subset existsiiCS(X , i, T ):if T = 0
return ?
if T < 0 or n = 0
return N
YCS(X , i 1, T )if Y 6= N
return Y
YCS(X , i 1, T X [i])if Y 6= N
return Y [ {X [i]}return N
Figure �.6. A recursive backtracking algorithm for the construction version of S�����S��.

�.�

The General Pattern

Backtracking algorithms are commonly used to make a sequence of decisions, withthe goal of building a recursively defined structure satisfying certain constraints.
Often (but not always) this goal structure is itself a sequence. For example:• In the n-queens problem, the goal is a sequence of queen positions, one ineach row, such that no two queens attack each other. For each row, thealgorithm decides where to place the queen.
• In the game tree problem, the goal is a sequence of legal moves, such thateach move is as good as possible for the player making it. For each gamestate, the algorithm decides the best possible next move.
• In the S
S
problem, the goal is a sequence of input elements thathave a particular sum. For each input element, the algorithm decides whether
to include it in the output sequence or not.
(Hang on, why is the goal of subset sum finding a sequence? That was adeliberate design decision. We imposed a convenient ordering on the input
set—by representing it using an array, as opposed to some other more amorphous
data structure—that we can exploit in our recursive algorithm.)
In each recursive call to the backtracking algorithm, we need to make exactly
one decision, and our choice must be consistent with all previous decisions.
Thus, each recursive call requires not only the portion of the input data we have
not yet processed, but also a suitable summary of the decisions we have alreadymade. For the sake of efficiency, the summary of past decisions should be as
small as possible. For example:���. B�����������

• For the n-queens problem, we must pass in not only the number of empty
rows, but the positions of all previously placed queens. Here, unfortunately,
we must remember our past decisions in complete detail.
• For the game tree problem, we only need to pass in the current state of thegame, including the identity of the next player. We don’t need to remember
anything about our past decisions, because who wins from a given gamestate does not depend on the moves that created that state.
• For the S
S
problem, we need to pass in both the remaining available
integers and the remaining target value, which is the original target value
minus the sum of the previously chosen elements. Precisely which elements
were previously chosen is unimportant.
When we design new recursive backtracking algorithms, we must figure out inadvance what information we will need about past decisions in the middle of
the algorithm. If this information is nontrivial, our recursive algorithm mightneed to solve a more general problem than the one we were originally asked tosolve. (We’ve seen this kind of generalization before: To find the median of anunsorted array in linear time, we derived an algorithm to select the kth smallest
element for arbitrary k.)
Finally, once we’ve figured out what recursive problem we really need tosolve, we solve that problem by recursive brute force: Try all possibilities forthe next decision that are consistent with past decisions, and let the Recursion
Fairy worry about the rest. No being clever here. No skipping “obviously” stupid
choices. Try everything. You can make the algorithm faster later.

�.�

Text Segmentation (Interpunctio Verborum)

Suppose you are given a string of letters representing text in some foreign
language, but without any spaces or punctuation, and you want to break thisstring into its individual constituent words. For example, you might be given
the following passage from Cicero’s famous oration in defense of Lucius Licinius
Murena in, in the standard scriptio continua of classical Latin:
Many games appear to violate this independence condition. For example, the standard rulesof both chess and checkers allow a player to declare a draw if the same arrangement of pieces
occurs three times, and the Chinese rules for go simply forbid repeating any earlier arrangementof stones. Thus, for these games, a game state formally includes not only the current positions of
the pieces but the entire history of previous moves.
In·fact·most·classical·Latin·manuscripts·separated·words·with·small·dots·called·interpuncts.
Interpunctuation all but disappeared by the rd century in favor of scriptio continua. Empty
spaces between words were introduced by Irish monks in the th century and slowly spread
across Europe over the next several centuries. Scriptio continua survives in early st-century
English in the form of URLs and hashtags. #octotherps�lyfe8��.�. Text Segmentation (Interpunctio Verborum)

PRIMVSDIGNITASINTAMTENVISCIENTIANONPOTESTESSERESENIMSVNTPARVAEPROPEINSINGVLISLITTERISATQVEINTERPVNCTIONIBUSVERBORVMOCCVPATAE
A fluent Latin reader would parse this string (in modern orthography) as Primus
dignitas in tam tenui scientia non potest esse; res enim sunt parvae, prope in singulis
litteris atque interpunctionibus verborum occupatae. Text segmentation is not
only a problem in classical Latin and Greek, but in several modern languages
and scripts including Balinese, Burmese, Chinese, Japanese, Javanese, Khmer,
Lao, Thai, Tibetan, and Vietnamese. Similar problems arise in segmenting
unpunctuated English text into sentences, segmenting text into lines fortypesetting, speech and handwriting recognition, curve simplification, andseveral types of time-series analysis. For purposes of illustration, I’ll stick tosegmenting sequences of letters in the modern English alphabet into modern
English words.
Of course, some strings can be segmented in several different ways; forexample, BOTHEARTHANDSATURNSPIN can be decomposed into English words
as either BOTH·EARTH·AND·SATURN·SPIN or BOT·HEART·HANDS·AT·URNS·PIN,
among many other possibilities. For now, let’s consider an extremely simple
segmentation problem: Given a string of characters, can it be segmented into
English words at all?
To make the problem concrete (and language-agnostic), let’s assume wehave access to a subroutine I W(w) that takes a string w as input, andreturns T
if w is a “word”, or F
if w is not a “word”. For example, if
we are trying to decompose the input string into palindromes, then a “word”
is a synonym for “palindrome”, and therefore I W(ROTATOR) = T
but
I W(PALINDROME) = F.
Just like the S
S
problem, the input structure is a sequence, thistime containing letters instead of numbers, so it is natural to consider a decision
process that consumes the input characters in order from left to right. Similarly,
the output structure is a sequence of words, so it is natural to consider a processthat produces the output words in order from left to right. Thus, jumping into
the middle of the segmentation process, we might imagine the following picture:

BLUE

STEM

UNIT

ROBOT

HEARTHANDSATURNSPIN

Loosely translated: “First of all, dignity in such paltry knowledge is impossible; this is trivial
stuff, mostly concerned with individual letters and the placement of points between words.”
Cicero was openly mocking the legal expertise of his friend(!) and noted jurist Servius Sulpicius
Rufus, who had accused Murena of bribery, after Murena defeated Rufus in election for consul.
Murena was acquitted, thanks in part to Cicero’s acerbic defense, although he was almost certainly
guilty. #librapondo #nunquamest�delis
St. Augustine’s De doctrina Christiana devotes an entire chapter to removing ambiguity from
Latin scripture by adding punctuation.

8��. B�����������

Here the black bar separates our past decisions—splitting the first letters into
four words—from the portion of the input string that we have not yet processed.
The next stage in our imagined process is to decide where the next word in
the output sequence ends. For this specific example, there are four possibilities
for the next output word—HE, HEAR, HEART, and HEARTH. We have no idea whichof these choices, if any, is consistent with a complete segmentation of the input
string. We could be “smart” at this point and try to figure out which choices
are good, but that would require thinking! Instead, let’s “stupidly” try every
possibility by brute force, and let the Recursion Fairy do all the real work.
• First tentatively accept HE as the next word, and let the Recursion Fairy makethe rest of the decisions.

BLUE

STEM

UNIT

ROBOT

HE

ARTHANDSATURNSPIN• Then tentatively accept HEAR as the next word, and let the Recursion Fairy
make the rest of the decisions.

BLUE

STEM

UNIT

ROBOT

HEAR

THANDSATURNSPIN• Then tentatively accept HEART as the next word, and let the Recursion Fairy
make the rest of the decisions.

BLUE

STEM

UNIT

ROBOT

HEART

HANDSATURNSPIN• Finally, tentatively accept HEARTH as the next word, and let the Recursion
Fairy make the rest of the decisions.

BLUE

STEM

UNIT

ROBOT

HEARTHANDSATURNSPIN

As long as the Recursion Fairy reports success at least once, we report success.
On the other hand, if the Recursion Fairy never reports success—in particular, if
the set of possible next words is empty—then we report failure.
None of our past decisions affect which choices are available now; all thatmatters is the suffix of characters that we have not yet processed. In particular,
several different sequences of past decisions could lead us to the same suffix,
but they all leave us with exactly the same set of choices for that suffix.

BLUE
BLUEST

STEM
EMU

UNIT
NITRO

ROBOT

HEARTHANDSATURNSPIN

BOTHEARTHANDSATURNSPIN

Thus, we can simplify our picture of the recursive process by discarding everythingleft of the black bar:

HEARTHANDSATURNSPIN
8��.�. Text Segmentation (Interpunctio Verborum)

We are now left with a simple and natural backtracking strategy: Select the first
output word, and recursively segment the rest of the input string.
To get a complete recursive algorithm, we need a base case. Our recursive
strategy breaks down when we reach the end of the input string, because there
is no next word. Fortunately, the empty string has a unique segmentation into
zero words!
Putting all the pieces together, we arrive at the following simple recursivealgorithm:
S(A[1 .. n]):
if n = 0
return T
for i
1 to nif I W(A[1 .. i])
if S(A[i + 1 .. n])return T
return F

Index Formulation
In practice, passing arrays as input parameters is rather slow; we should reallyfind a more compact way to describe our recursive subproblems. For purposes ofdesigning the algorithm, it’s incredibly useful to treat the original input array as
a global variable, and then reformulate the problem and the algorithm in termsof array indices instead of explicit subarrays.
For our string segmentation problem, the argument of any recursive callis always a suffix A[i .. n] of the original input array. So if we treat the input
array A[1 .. n] as a global variable, we can reformulate our recursive problem asfollows:
Given an index i, find a segmentation of the suffix A[i .. n].
To describe our algorithm, we need two boolean functions:• For any indices i and j, let I W(i, j) = T
if and only if the substringA[i .. j] is a word. (We’re assuming this function is given to us.)• For any index i, let Splittable(i) = T
if and only if the suffix A[i .. n] canbe split into words. (This is the function we need to implement.)
For example, I W(1, n) = T
if and only if the entire input string is asingle word, and Splittable(1) = T
if and only if the entire input string canbe segmented. Our earlier recursive strategy gives us the following recurrence:8>
if i > n<TnSplittable(i) = W>
I W(i, j) ^ Splittable( j + 1) otherwise
:
j=i

8�

�. B�����������

This is exactly the same algorithm as we saw earlier; the only thing we’vechanged is the notation. The similarity is even more apparent if we rewrite therecurrence in pseudocode:
hhIs the suf�x A[i .. n] Splittable?ii
S(i):
if i > nreturn T
for j
i to nif I W(i, j)
if S( j + 1)
return T
return F

Although it may look like a trivial notational difference, using index notation
instead of array notation is an important habit, not only to speed up backtracking
algorithms in practice, but for developing dynamic programming algorithms,
which we discuss in the next chapter.
™Analysis

It should come as no surprise that most backtracking algorithms have exponential
worst-case running times. Analyzing the precise running times of many ofthese algorithms requires techniques that are beyond the scope of this book.
Fortunately, most of the backtracking algorithms we will encounter in this book
are only intermediate results on the way to more efficient algorithms, whichmeans their exact worst-case running time is not actually important. (First
make it work; then make it fast.)
But just for fun, let’s analyze the running time of our recursive algorithmS. Because we don’t know what I W
is doing, we can’t know
how long each call to I W
takes, so we’re forced to analyze the running
time in terms of the number of calls to I W. S
calls I W
on every prefix of the input string, and possibly calls itself recursively on every
suffix of the output string. Thus, the “running time” of S
obeys thescary-looking recurrence
T (n) n 1
Xi=0

T (i) + O(n)This really isn’t as bad as it looks, especially once you’ve seen the trick.
First, we replace the O(n) term with an explicit expression ↵n, for some
unknown (and ultimately unimportant) constant ↵. Second, we conservatively
In fact, as long as I W

8�runs in polynomial time, S

runs in O(2n ) time.

�.�. Text Segmentation (Interpunctio Verborum)

assume that the algorithm actually makes every possible recursive call. Then
we can transform the “full history” recurrence into a “limited history” recurrenceby subtracting the recurrence for T (n 1), as follows:
T (n) ==) T (n)

n 1
X
i=0
n 2
X

T (i) + ↵n

T (n

1) =

T (n

1) = T (ni=0

T (i) + ↵(n1)1) + ↵

This final recurrence simplifies to T (n) = 2T (n 1) + ↵. At this point, we canconfidently guess (or derive via recursion trees, or remember from our Towerof Hanoi analysis) that T (n) = O(2n ); indeed, this upper bound is not hard toprove by induction from the original full-history recurrence.
Moreover, this analysis is tight. There are exactly 2n 1 possible ways tosegment a string of length n—each input character either ends a word or doesn’t,
except the last input character, which always ends the last word. In the worst
case, our S
algorithm explores each of these 2n 1 possibilities.

Variants
Now that we have the basic recursion pattern in hand, we can use it to solve
many different variants of the segmentation problem, just as we did for theS
S
problem. Here I’ll describe just one example; more variations are
considered in the exercises. As usual, the original input to our problem is anarray A[1 .. n].
If a string can be segmented in more than one sequence of words, we may
want to find the best segmentation according to some criterion; conversely, if
the input string cannot be segmented into words, we may want to compute thebest segmentation we can find, rather than merely reporting failure. To meetboth of these goals, suppose we have access to a second function S
thattakes a string as input and returns a numerical value. For example, we mightassign higher scores to longer or more common words, lower scores to shorteror more obscure words, slightly negative scores for minor spelling errors, andmore negative scores to obvious non-words. Our goal is to find a segmentationthat maximizes the sum of the scores of the segments.
This assumption is wildly conservative for English word segmentation, since most strings ofletters are not English words, but not for the similar problem of segmenting sequences of English
words into grammatically correct English sentences. Consider, for example, a sequence of n copiesof the word “buffalo”, or n copies of the work “police”, or n copies of the word “can”, for any
positive integer n. (At the Moulin Rouge, dances that are preservable in metal cylinders by otherdances have the opportunity to fire dances that happen in prison restroom trash receptacles.)8��. B�����������

For any index i, let MaxScore(i) denote the maximum score of any segmentation of the suffix A[i .. n]; we need to compute MaxScore(1). This function
satisfies the following recurrence:(0
if i > n
MaxScore(i) =max S(A[i .. j]) + MaxScore( j + 1) otherwisei jnThis is essentially the same recurrence as the one we developed for Splittable;
the only difference is that the boolean operations _ and ^ have been replacedby the numerical operations max and +.

�.6

Longest Increasing Subsequence

For any sequence S, a subsequence of S is another sequence obtained from S bydeleting zero or more elements, without changing the order of the remaining
elements; the elements of the subsequence need not be contiguous in S. For
example, when you drive down a major street in any city, you drive througha sequence of intersections with traffic lights, but you only have to stop at a
subsequence of those intersections, where the traffic lights are red. If you’re very
lucky, you never stop at all: the empty sequence is a subsequence of S. On theother hand, if you’re very unlucky, you may have to stop at every intersection: S
is a subsequence of itself.
As another example, the strings BENT, ACKACK, SQUARING, and SUBSEQUENT
are all subsequences of the string SUBSEQUENCEBACKTRACKING, as are the empty
string and the entire string SUBSEQUENCEBACKTRACKING, but the strings QUEUE
and EQUUS and TALLYHO are not. A subsequence whose elements are contiguousin the original sequence is called a substring; for example, MASHER and LAUGHTER
are both subsequences of MANSLAUGHTER, but only LAUGHTER is a substring.
Now suppose we are given a sequence of integers, and we need to find thelongest subsequence whose elements are in increasing order. More concretely,
the input is an integer array A[1 .. n], and we need to compute the longest
possible sequence of indices 1  i1 < i2 < · · · < i`  n such that A[ik ] < A[ik+1 ]for all k.
One natural approach to building this longest increasing subsequence is todecide, for each index j in order from 1 to n, whether or not to include A[ j] inthe subsequence. Jumping into the middle of this decision sequence, we might
imagine the following picture:
3 1 4 1 5 9 2 6 5 3

5? 8 9 7 9 3 2 3 8 4 6 2 6As in our earlier text segmentation examples, the black bar separates our pastdecisions from the portion of the input we have not yet processed. Numbers we86�.6. Longest Increasing Subsequence

have already decided to include are highlighted and bold; numbers we havealready decided to exclude are grayed out. (Notice that the numbers we’ve
decided to include are increasing!) Our algorithm must decide whether or not
to include the number immediately after the black bar.
In this example, we definitely cannot include 5, because then the selected
numbers would no longer be in increasing order. So let’s skip ahead to the next
decision:
3 1 4 1 5 9 2 6 5 3 5

8? 9 7 9 3 2 3 8 4 6 2 6Now we can include 8, but it’s not obvious whether we should. Rather thantrying to be “smart”, our backtracking algorithm will use simple brute force.
• First tentatively include the 8, and let the Recursion Fairy make the rest of
the decisions.
• Then tentatively exclude the 8, and let the Recursion Fairy make the rest of
the decisions.
Whichever choice leads to a longer increasing subsequence is the right one.
(This is precisely the same recursion pattern we used to solve S
S .)Now for the key question: What do we need to remember about our pastdecisions? We can only include A[ j] if the resulting subsequence is in increasingorder. If we assume (inductively!) that the numbers previously selected fromA[1 .. j 1] are in increasing order, then we can include A[ j] if and only if
A[ j] is larger than the last number selected from A[1 .. j 1]. Thus, the only
information we need about the past is the last number selected so far. We can
now revise our pictures by erasing everything we don’t need:6

5? 8 9 7 9 3 2 3 8 4 6 2 6

6

8? 9 7 9 3 2 3 8 4 6 2 6

So the problem our recursive strategy is actually solving is the following:
Given an integer prev and an array A[1 .. n], find the longest increasing
subsequence of A in which every element is larger than prev.
As usual, our recursive strategy requires a base case. Our current strategy
breaks down when we get to the end of the array, because there is no “nextnumber” to consider. But an empty array has exactly one subsequence, namely,
the empty sequence. Vacuously, every element in the empty sequence is larger
than whatever value you want, and every pair of elements in the empty sequenceappears in increasing order. Thus, the longest increasing subsequence of theempty array has length 0.
Here’s the resulting recursive algorithm:8��. B�����������

LIS(prev, A[1 .. n]):
if n = 0
return 0
else if A[1]  prev
return LIS(prev, A[2 .. n)elseskip LIS(prev, A[2 .. n])take LIS(A[1], A[2 .. n]) + 1
return max{skip, take}Okay, but remember that passing arrays around on the call stack is expensive;
let’s try to rephrase everything in terms of array indices, assuming that the arrayA[1 .. n] is a global variable. The integer prev is typically an array element A[i],and the remaining array is always a suffix A[ j .. n] of the original input array.
So we can reformulate our recursive problem as follows:
Given two indices i and j, where i < j, find the longest increasing
subsequence of A[ j .. n] in which every element is larger than A[i].
Let LISbigger(i, j) denote the length of the longest increasing subsequence ofA[ j .. n] in which every element is larger than A[i]. Our recursive strategy gives
us the following recurrence:
8
0
>
>
>
<LISbigger(i, j + 1)
LISbigger(i, j) =⇢>LISbigger(i, j + 1)>>
:max
1 + LISbigger( j, j + 1)

if j > nif A[i]A[ j]otherwise

Alternatively, if you prefer pseudocode:
LIS(i, j):
if j > nreturn 0
else if A[i] A[ j]return LIS(i, j + 1)
else
skip LIS(i, j + 1)
take LIS( j, j + 1) + 1
return max{skip, take}

Finally, we need to connect our recursive strategy to the original problem:
Finding the longest increasing subsequence of an array with no other constraints.
The simplest approach is to add an artificial sentinel value 1 to the beginningof the array.
88

�.�. Longest Increasing Subsequence, Take �

LIS(A[1 .. n]):A[0]1return LIS(0, 1)The running time of LIS
satisfies the Hanoi recurrence T (n) 
2T (n 1) + O(1), which as usual implies that T (n) = O(2n ). We really shouldn’t
be surprised by this running time; in the worst case, the algorithm examines
each of the 2n subsequences of the input array.

�.�

Longest Increasing Subsequence, Take �This is not the only backtracking strategy we can use to find longest increasing
subsequences. Instead of considering the input sequence one element at a time,
we could try to construct the output sequence one element at a time. That is,
instead of asking “Is A[i] the next element of the output sequence?”, we could
ask directly, “Where is the next element of the output sequence, if any?”
Jumping into the middle of this strategy, we might be faced with the following
picture. Suppose we just decided to include the 6 just left of the black bar in
our output sequence, and we need to decide which element to the right of thebar to include next.
3 1 4 1 5 9 2 6

5? 3? 5? 8? 9? 7? 9? 3? 2? 3? 8? 4? 6? 2? 6?

Of course, we can only include numbers on the right that are greater than 6;otherwise, our output sequence would not be increasing.
3 1 4 1 5 9 2 6

5 3 5 8? 9? 7? 9? 3 2 3 8? 4 6 2 6

But we have no idea which of those larger numbers is the best choice, and trying
to cleverly figure out the best choice is too much work, and it’s only going to get
us into trouble anyway. Instead, we enumerate all possibilities by brute force,and let the Recursion Fairy evaluate each one.
3 1 4 1 5 9 2 6 5 3 5 8

9 7 9 3 2 3 8 4 6 2 6

3 1 4 1 5 9 2 6 5 3 5 8 9

7 9 3 2 3 8 4 6 2 6

3 1 4 1 5 9 2 6 5 3 5 8 9 7

9 3 2 3 8 4 6 2 6

3 1 4 1 5 9 2 6 5 3 5 8 9 7 93 2 3 8 4 6 2 6

3 1 4 1 5 9 2 6 5 3 5 8 9 7 9 3 2 3 8

4 6 2 68��. B�����������

The subset of numbers we can consider as the next element depends only
on the last number we decided to include. Thus, we can simplify our picture of
the decision process by discarding everything to the left of the bar except thelast number we decided to include.
6

5 3 5 8 9 7 9 3 2 3 8 4 6 2 6The remaining sequence of numbers is just a suffix of the original input array.
Thus, if we think of the input array A[1 .. n] as a global variable, we can formally
express our recursive problem in terms of indices as follows:
Given an index i, find the longest increasing subsequence of A[i .. n] thatbegins with A[i].
Let LISfirst(i) denote the length of the longest increasing subsequence of A[i .. n]that begins with A[i]. We can now formulate our recursive backtracking strategy
as the following recursive definition:
LISfirst(i) = 1 + max LISfirst( j)j > i and A[ j] > A[i]Because we are dealing with sets of natural numbers, we define max ? = 0. Thenwe automatically have LISfirst(i) = 1 if A[ j]  A[i] for all j > i; in particular,
LISfirst(n) = 1. These are the base cases for our recurrence.
We can also express this recursive definition in pseudocode as follows:
LIS
best
for j

(i):
0
i + 1 to n
if A[ j] > A[i]best max{best, LIS
return 1 + best( j)}Finally, we need to reconnect this recursive algorithm to our original
problem—finding the longest increasing subsequence without knowing its
first element. One natural approach that works is to try all possible first elements by brute force. Equivalently, we can add a sentinel element 1 to thebeginning of the array, find the longest increasing subsequence that starts withthe sentinel, and finally ignore the sentinel.
LIS(A[1 .. n]):best 0for i
1 to nbest max{best, LIS
return best
��

(i)}

LIS(A[1 .. n]):A[0]1return LIS(0)1

�.8. Optimal Binary Search Trees

�.8

Optimal Binary Search Trees

Our final example combines recursive backtracking with the divide-and-conquer
strategy. Recall that the running time for a successful search in a binary searchtree is proportional to the number of ancestors of the target node. As a result,
the worst-case search time is proportional to the depth of the tree. Thus, tominimize the worst-case search time, the height of the tree should be as small
as possible; by this metric, the ideal tree is perfectly balanced.
In many applications of binary search trees, however, it is more important tominimize the total cost of several searches rather than the worst-case cost of asingle search. If x is a more frequent search target than y, we can save time bybuilding a tree where the depth of x is smaller than the depth of y, even if thatmeans increasing the overall depth of the tree. A perfectly balanced tree is not
the best choice if some items are significantly more popular than others. In fact,a totally unbalanced tree with depth ⌦(n) might actually be the best choice!
This situation suggests the following problem. Suppose we are given asorted array of keys A[1 .. n] and an array of corresponding access frequencies
f [1 .. n]. Our task is to build the binary search tree that minimizes the total
search time, assuming that there will be exactly f [i] searches for each key A[i].
Before we think about how to solve this problem, we should first comeup with a good recursive definition of the function we are trying to optimize!
Suppose we are also given a binary search tree T with n nodes. Let v1 , v2 , . . . , vn
be the nodes of T , indexed in sorted order, so that each node vi stores thecorresponding key A[i]. Then ignoring constant factors, the total cost of
performing all the binary searches is given by the following expression:
Cost(T, f [1 .. n]) :=

n
X
i=1

f [i] · #ancestors of vi in T(⇤)

Now suppose vr is the root of T ; by definition, vr is an ancestor of every node
in T . If i < r, then all ancestors of vi except the root are in the left subtree of T .
Similarly, if i > r, then all ancestors of vi except the root are in the right subtreeof T . Thus, we can partition the cost function into three parts as follows:
Cost(T, f [1 .. n]) =

n
X
i=1

f [i] ++

r 1
X

f [i] · #ancestors of vi in left(T )

i=1
n
X

i=r+1

f [i] · #ancestors of vi in right(T )The second and third summations look exactly like our original definition (⇤)
An ancestor of a node v is either the node itself or an ancestor of the parent of v. A proper
ancestor of v is either the parent of v or a proper ancestor of the parent of v.

���. B�����������

for Cost(T, f [1 .. n]). Simple substitution now gives us a recurrence for Cost:
Cost(T, f [1 .. n]) =

n
X
i=1

f [i] + Cost(left(T ), f [1 .. r1])

+ Cost(right(T ), f [r + 1 .. n])

The base case for this recurrence is, as usual, n = 0; the cost of performing nosearches in the empty tree is zero.
Now our task is to compute the tree Topt that minimizes this cost function.
Suppose we somehow magically knew that the root of Topt is vr . Then therecursive definition of Cost(T, f ) immediately implies that the left subtree
left(Topt ) must be the optimal search tree for the keys A[1 .. r 1] and accessfrequencies f [1 .. r 1]. Similarly, the right subtree right(Topt ) must be theoptimal search tree for the keys A[r + 1 .. n] and access frequencies f [r + 1 .. n].
Once we choose the correct key to store at the root, the Recursion Fairy
will construct the rest of the optimal tree.
More generally, let OptCost(i, k) denote the total cost of the optimal searchtree for the interval of frequencies f [i .. k]. This function obeys the following
recurrence.
8>0
if i > k><®
´k
OptCost(i, k) = X
OptCost(i, r 1)>
f [i] + minotherwise>:irk+ OptCost(r + 1, k)
j=i

The base case correctly indicates that the minimum possible cost to performzero searches into the empty set is zero! Our original problem is to compute
OptCost(1, n).
This recursive definition can be translated mechanically into a recursive
backtracking algorithm to compute OptCost(1, n). Not surprisingly, the running
time of this algorithm is exponential. In the next chapter, we’ll see how to
reduce the running time to polynomial, so there’s not much point in computing
the precise running time. . .
™Analysis. . . unless you’re into that sort of thing. Just for the fun of it, let’s figure out
how slow this backtracking algorithm actually is. The running time satisfies therecurrencenX
T (n) =T (k 1) + T (n k) + O(n).
k=1Pn
The O(n) term comes from computing the total number of searches i=1 f [i].
Yeah, that’s one ugly recurrence, but we can solve it using exactly the same��

Exercises

subtraction trick we used before. We replace the O( ) notation with an explicit
constant, regroup and collect identical terms, subtract the recurrence for T (n 1)
to get rid of the summation, and then regroup again.
T (n) = 2n 1
X

T (k) + ↵n

k=0

T (n

1) = 2n 2
X

T (k) + ↵(n

1)

k=0

T (n)

T (n

1) = 2T (n1) + ↵

T (n) = 3T (n1) + ↵

Hey, that doesn’t look so bad after all. The recursion tree method immediately
gives us the solution T (n) = O(3n ) (or we can just guess and confirm by
induction).
This analysis implies that our recursive algorithm does not examine all
possible binary search trees! The number of binary search trees with n vertices
satisfies the recurrence
N (n) =

n 1
X
r=1

N (r

1) · N (nr) ,pwhich has the closed-form solution N (n) = ⇥(4n / n). (No, that’s not obvious.)
Our algorithm saves considerable time by searching independently for the optimal
left and right subtrees for each root. A full enumeration of binary search trees
would consider all possible pairs of left and right subtrees; hence the product in
the recurrence for N (n).

Exercises. Describe recursive algorithms for the following generalizations of the S
S
problem:-(a) Given an array X [1 .. n] of positive integers and an integer T , computethe number of subsets of X whose elements sum to T .
(b) Given two arrays X [1 .. n] and W [1 .. n] of positive integers and an
integer T , where each W [i] denotes the weight of the corresponding
element X [i], compute the maximum weight subset of X whose elements
sum to T . If no subset of X sums to T , your algorithm should return 1.
. Describe recursive algorithms for the following variants of the text segmentation problem. Assume that you have a subroutine I W
that takes an���. B�����������

array of characters as input and returns T“word”.

if and only if that string is a(a) Given an array A[1 .. n] of characters, compute the number of partitionsof A into words. For example, given the string ARTISTOIL, your algorithm
should return 2, for the partitions ARTIST·OIL and ART·IS·TOIL.
(b) Given two arrays A[1 .. n] and B[1 .. n] of characters, decide whether A
and B can be partitioned into words at the same indices. For example,
the strings BOTHEARTHANDSATURNSPIN and PINSTARTRAPSANDRAGSLAP
can be partitioned into words at the same indices as follows:

BOT·HEART·HAND·SAT·URNS·PIN
PIN·START·RAPS·AND·RAGS·LAP(c) Given two arrays A[1 .. n] and B[1 .. n] of characters, compute the numberof different ways that A and B can be partitioned into words at the same
indices.
. An addition chain for an integer n is an increasing sequence of integers
that starts with 1 and ends with n, such that each entry after the firstis the sum of two earlier entries. More formally, the integer sequencex 0 < x 1 < x 2 < · · · < x ` is an addition chain for n if and only if• x 0 = 1,
• x ` = n, and• for every index k > 0, there are indices i  j < k such that x k = x i + x j .

The `ength of an addition chain is the number of elements minus 1; wedon’t bother to count the first entry. For example, h1, 2, 3, 5, 10, 20, 23, 46,
92, 184, 187, 374i is an addition chain for 374 of length 11.

(a) Describe a recursive backtracking algorithm to compute a minimumlength addition chain for a given positive integer n. Don’t analyze or
optimize your algorithm’s running time, except to satisfy your own
curiosity. A correct algorithm whose running time is exponential in n issufficient for full credit. [Hint: This problem is a lot more like n Queens
than text segmentation.]™

(b) Describe a recursive backtracking algorithm to compute a minimumlength addition chain for a given positive integer n in time that is
sub-exponential in n. [Hint: You may find the results of certain Egyptianrope-fasteners, Indus-River prosodists, and Russian peasants helpful.]. (a) Let A[1 .. m] and B[1 .. n] be two arbitrary arrays. A common subsequenceof A and B is both a subsequence of A and a subsequence of B. Givea simple recursive definition for the function lcs(A, B), which gives thelength of the longest common subsequence of A and B.
��Exercises(b) Let A[1 .. m] and B[1 .. n] be two arbitrary arrays. A common supersequence of A and B is another sequence that contains both A and B
as subsequences. Give a simple recursive definition for the function
scs(A, B), which gives the length of the shortest common supersequenceof A and B.
(c) Call a sequence X [1 .. n] of numbers bitonic if there is an index i with
1 < i < n, such that the prefix X [1 .. i] is increasing and the suffix
X [i .. n] is decreasing. Give a simple recursive definition for the function
lbs(A), which gives the length of the longest bitonic subsequence of anarbitrary array A of integers.
(d) Call a sequence X [1 .. n] oscillating if X [i] < X [i + 1] for all even i, andX [i] > X [i + 1] for all odd i. Give a simple recursive definition for
the function los(A), which gives the length of the longest oscillating
subsequence of an arbitrary array A of integers.
(e) Give a simple recursive definition for the function sos(A), which gives
the length of the shortest oscillating supersequence of an arbitrary array
A of integers.
(f) Call a sequence X [1 .. n] convex if 2 · X [i] < X [i 1] + X [i + 1] for all i.
Give a simple recursive definition for the function lxs(A), which gives
the length of the longest convex subsequence of an arbitrary array A of
integers.
. For each of the following problems, the input consists of two arrays X [1 .. k]
and Y [1 .. n] where k  n.
(a) Describe a recursive backtracking algorithm to determine whether X isa subsequence of Y . For example, the string PPAP is a subsequence ofthe string PENPINEAPPLEAPPLEPEN.

(b) Describe a recursive backtracking algorithm to find the smallest numberof symbols that can be removed from Y so that X is no longer asubsequence. Equivalently, your algorithm should find the longest
subsequence of Y that is not a supersequence of X . For example, after
removing removing two symbols from the string PENPINEAPPLEAPPLEPEN,
the string PPAP is no longer a subsequence.
™

(c) Describe a recursive backtracking algorithm to determine whether X
occurs as two disjoint subsequences of Y . For example, the string PPAP appears as two disjoint subsequences in the string PENPINEAPPLEAPPLEPEN.
Don’t analyze the running times of your algorithms, except to satisfy yourown curiosity. All three algorithms run in exponential time; we’ll improvethat later, so the precise running time isn’t particularly important.
���. B�����������

. This problem asks you to design backtracking algorithms to find the cost of
an optimal binary search tree that satisfies additional balance constraints.
Your input consists of a sorted array A[1 .. n] of search keys and an arrayf [1 .. n] of frequency counts, where f [i] is the number of searches for A[i].
This is exactly the same cost function as described in Section . . But
now your task is to compute an optimal tree that satisfies some additional
constraints.
(a) AVL trees were the earliest self-balancing balanced binary search trees,
first described inby Georgy Adelson-Velsky and Evgenii Landis. An
AVL tree is a binary search tree where for every node v, the height of
the left subtree of v and the height of the right subtree of v differ by atmost one.
Describe a recursive backtracking algorithm to construct an optimal
AVL tree for a given set of search keys and frequencies.
(b) Symmetric binary B-trees are another self-balancing binary trees, firstdescribed by Rudolf Bayer in; these are better known by the namered-black trees, after a somewhat simpler reformulation by Leo Guibas
and Bob Sedgwick in. A red-black tree is a binary search tree withthe following additional constraints:• Every node is either red or black.
• Every red node has a black parent.
• Every root-to-leaf path contains the same number of black nodes.
Describe a recursive backtracking algorithm to construct an optimal
red-black tree for a given set of search keys and frequencies.
(c) AA trees were proposed by proposed by Arne Andersson inandslightly simplified (and named) by Mark Allen Weiss in. AA trees arealso known as left-leaning red-black trees, after a symmetric reformulation(with different rebalancing algorithms) by Bob Sedgewick in. An
AA tree is a red-black tree with one additional constraint:• No left child is red.
Describe a recursive backtracking algorithm to construct an optimal AA
tree for a given set of search keys and frequencies.
Don’t analyze the running times of your algorithms, except to satisfy yourown curiosity. All three algorithms run in exponential time; we’ll improvethat later, so the precise running times aren’t particularly important.
For more backtracking exercises, see the next chapter!
Sedgwick’s reformulation requires that no right child is red. Whatever. Andersson andSedgwick are strangely silent on which end of the egg to eat first.

�6