Lecture 10 | Programming Abstractions (Stanford)
-
0:00 - 0:11
-
0:11 - 0:14This presentation is delivered by the Stanford Center for Professional Development.
-
0:23 - 0:27Today I'm gonna keep talking a little bit more about another procedural
recursion example and -
0:27 - 0:31then go on to talk about, kind of,
the approach for recursive backtracking, -
0:31 - 0:36which is taking those procedural recursion examples and kind of twisting them around and doing new things with them. Okay.
-
0:36 - 0:39This is the last problem I did at the end of
-
0:39 - 0:42Wednesday's lecture. It's a very, very important problem, so I don't actually
-
0:42 - 0:46want to move away from it until I feel that I'm getting some signs from you
-
0:46 - 0:47guys that we're
-
0:47 - 0:49
-
0:49 - 0:51getting some understanding of this because it turns out it forms the basis of a lot of
-
0:51 - 0:55other solutions end up just becoming permutations, you know, at the core of it.
-
0:55 - 0:56So it's
-
0:56 - 1:01a pretty useful pattern to have [inaudible]
-
1:01 - 1:05list the permutations of a string. So you've got the string, you know, A B C D, and it's
-
1:05 - 1:07gonna print all the A C D A B C D
-
1:07 - 1:12A variations that you can get by rearranging all the letters.
-
1:12 - 1:15It's a deceptively short piece of
-
1:15 - 1:17code that does what's being done here
-
1:17 - 1:20-is that it breaks it down in terms of there being the permutation that's
-
1:20 - 1:24assembled so far, and then the remaining characters that haven't yet been looked
-
1:24 - 1:25at, and so
-
1:25 - 1:27at each recursive call it's gonna
-
1:27 - 1:30shuffle one character from the
-
1:30 - 1:33remainder onto the thing that's been chosen so far. So chose the next
-
1:33 - 1:37character in the permutation, and eventually, when the rest is empty,
-
1:37 - 1:41then all of the characters have been moved over, and have been laid down in
-
1:41 - 1:44permutation, then what I have is a full permutation of the length end.
-
1:44 - 1:48In the case where rest is not empty, I've still got some choices to make. The number of
-
1:48 - 1:52choices is exactly equal to the number of characters I have left in
-
1:52 - 1:53rest,
-
1:53 - 1:55and for each of the remaining characters at this point, maybe there's just C
-
1:55 - 1:56and D left,
-
1:56 - 1:58then I'm gonna try each of them
-
1:58 - 2:03as the next character in the permutation, and then permute what remains after
-
2:03 - 2:04having made that choice.
-
2:04 - 2:05And so this is
-
2:05 - 2:07[inaudible] operations here of
-
2:07 - 2:09attaching that [inaudible]
-
2:09 - 2:13into the existing so far, and then subtracting it
-
2:13 - 2:14out of the rest
-
2:14 - 2:18to set up the arguments for that recursive call. A
-
2:18 - 2:21little bit at the end we talked about this idea of a wrapper function where
-
2:21 - 2:24the interface to list permutations from a client point of view probably just wants to
-
2:24 - 2:26be, here's a string to permute
-
2:26 - 2:27the fact that [inaudible]
-
2:27 - 2:31keep this housekeeping of what I've built so far is really any internal management
-
2:31 - 2:34issue, and isn't what I want to expose as part of the interface,
-
2:34 - 2:37so we in turn have just a really simple one line translation that the outer
-
2:37 - 2:40call just sets up and makes the call to the real recursive function setting up
-
2:40 - 2:44the right state for the housekeeping in this case, which is the
-
2:44 - 2:47permutation we've assembled at this point.
-
2:47 - 2:50So
-
2:50 - 2:53I'd like to ask you a few questions about this
-
2:53 - 2:56to see if we're kind of seeing the same things. Can
-
2:56 - 3:00someone tell me what is the first permutation that's printed by this
-
3:00 - 3:14if I put in the string A B C D?
-
3:14 - 3:17Anyone want to help me?
-
3:17 - 3:21A B C D. A B C D. So the exact string I gave it, right, is the one that it picks, right,
-
3:21 - 3:23the very first time, and that's because,
-
3:23 - 3:26if you look at the way the for loop is structured, the idea is that it's gonna make a
-
3:26 - 3:29choice and it's gonna move through the recursion. Well, the choice it always makes is to take
-
3:29 - 3:32the next character of rest and attach it to the permutation
-
3:32 - 3:36as its first time through the for loop. So the first time through the very first
-
3:36 - 3:38for loop it's got A B C D to chose, it chooses A,
-
3:38 - 3:43and now it recurs on A in the permutation and B C D to go. Well, the
-
3:43 - 3:46next call does exactly the same thing, chooses the first of what remains, which
-
3:46 - 3:49is B, attaches it to the permutation and keeps going.
-
3:49 - 3:50So the kind of
-
3:50 - 3:53deep arm of the recursion making that first choice and working its way down to
-
3:53 - 3:57the base case, right, right remember the recursion always goes deep. It goes down to the end of
-
3:57 - 3:57the
-
3:57 - 4:01-and bottoms on the recursion before it comes back and revisits any previous
-
4:01 - 4:03decision, will go A B C D,
-
4:03 - 4:04and then
-
4:04 - 4:08eventually come back and start trying other things, but that very first one,
-
4:08 - 4:11right, is all just the sequence there.
-
4:11 - 4:13The next one that's after it, right,
-
4:13 - 4:14is A B D C,
-
4:14 - 4:17which involved unmaking those last couple decisions.
-
4:17 - 4:19If I look at
-
4:19 - 4:22the tree that I have here that may help to sort of identify it.
-
4:22 - 4:24That permute of emptying A B C,
-
4:24 - 4:27the first choice it makes is go with A, and then the
-
4:27 - 4:30first choice it makes here is go with B, and so on, so that the first thing that we can see
-
4:30 - 4:34printed our here will be A B C D, we get to the base case.
-
4:34 - 4:36Once it's tried this, it'll come back to this one, and on this
-
4:36 - 4:39one it'll say, well, try the other characters. Well, there's no other
-
4:39 - 4:41characters. In fact, this one also finishes.
-
4:41 - 4:46It'll get back to here as it unwinds the stack the way the stack
-
4:46 - 4:49gets back to where it was previously in these recursive calls. And now it says, okay,
-
4:49 - 4:51and now try the ones that have,
-
4:51 - 4:54on the second iteration of that for loop, D in the front,
-
4:54 - 4:56and so it ends up putting A B D together,
-
4:56 - 4:58leaving C, and then getting A B D C. And
-
4:58 - 5:02then, so on kind of over here, the other variations, it will print all of the ones that have A
-
5:02 - 5:03in the front.
-
5:03 - 5:06There are eight of them.
-
5:06 - 5:07I believe three, two
-
5:07 - 5:10-no, six. Six of them
-
5:10 - 5:14that have A in the front, and we'll do all of those. And only after having done all of
-
5:14 - 5:18working out that whole part, which involves kind of the [inaudible] of this whole arm,
-
5:18 - 5:21will eventually unwind back to the initial permute call,
-
5:21 - 5:22
-
5:22 - 5:26and then say, okay, now try again. Go with B in the front and work your way
-
5:26 - 5:28down from reading the A C D behind it.
-
5:28 - 5:30So we'll see all the As
-
5:30 - 5:33then the bunch that lead with B, then the bunch that leads with C, and then finally the
-
5:33 - 5:36bunch that leads with D.
-
5:36 - 5:39It doesn't turn out -matter, actually, what order it visits them in because, in fact, all we
-
5:39 - 5:42cared about was seeing all of them. But part of what I'm trying to get with you
-
5:42 - 5:44is the sense of being
-
5:44 - 5:46able to look at that recursive code,
-
5:46 - 5:50and use your mind to kind of trace its activity and think about the
-
5:50 - 5:54progress that is made through those recursive calls. Just
-
5:54 - 5:57let me look at that code just for a second more and see if there's any else that I want to
-
5:57 - 5:59highlight for you.
-
5:59 - 6:05
-
6:05 - 6:08I think that's about what
-
6:08 - 6:08it's gonna do.
-
6:08 - 6:11So if you don't understand this cost, if there's something about it that confuses you, now
-
6:11 - 6:15would be an excellent time for you to ask a question that I could help
-
6:15 - 6:17kind of get your understanding
-
6:17 - 6:19made more clear. So
-
6:19 - 6:24when you look at this code, you feel like you believe it works? You understand it? [Inaudible]. I have a question.
-
6:24 - 6:29Is there a simple change you can make to this
-
6:29 - 6:29code
-
6:29 - 6:32so that it does combinations [inaudible]?
-
6:32 - 6:36Does combinations -you mean, like, will skip letters?
-
6:36 - 6:42Right. Yes. It turns out we're gonna make that change in not five minutes.
-
6:42 - 6:45In effect, what you would do -and there's a pretty simple change with
-
6:45 - 6:47this form. I'm gonna show you a slightly different way of doing it,
-
6:47 - 6:48but one way of doing it would be to say,
-
6:48 - 6:52well, give me the letter, don't attach it to next right? So right now, the
-
6:52 - 6:56choices are pick one of the letters that remain and then attach it to
-
6:56 - 7:00the permutation. Another option you could do was pick a letter and just discard it,
-
7:00 - 7:03right? And so, in which case, I wouldn't add it into so far.
-
7:03 - 7:06I would still subtract it from here, and I'd make another recursive call
-
7:06 - 7:07saying, now
-
7:07 - 7:10how about the permutations that don't involve A at all? And
-
7:10 - 7:14I would just drop it from the thing and I would recurs on just the B C D part. So
-
7:14 - 7:17a pretty simple change right here. I'm gonna show you there's a slightly different way to
-
7:17 - 7:21formulate the same thing in a little bit, but
-
7:21 - 7:27-anybody want to own up to having something that confuses them? [Inaudible] ask how you, like,
-
7:27 - 7:29what you would set up to test it?
-
7:29 - 7:30So [inaudible] one of
-
7:30 - 7:33the, you know, the easiest thing to do here, and I have the code kind of actually sitting over
-
7:33 - 7:35here just in case, right,
-
7:35 - 7:38hoping you would
-
7:38 - 7:41ask because right now I just have the most barebones sort of testing. It's like, yeah, what if I just,
-
7:41 - 7:44you know, throw some strings at it and see what happens, right?
-
7:44 - 7:45And so
-
7:45 - 7:49the easiest strings to throw at it would be things like, well what happens if I give it the empty
-
7:49 - 7:49string,
-
7:49 - 7:52right? You know, so it takes some really simple cases to start because you want to see, well what happens
-
7:52 - 7:55when, you know, you give it an empty input. Is it gonna blow up? And it's, like, the empty input,
-
7:55 - 7:58right, immediately realizes there's no choices and it says, well, look, there's nothing to
-
7:58 - 8:00print other than that empty string.
-
8:00 - 8:02What if I give it a single character string?
-
8:02 - 8:04Right? I get that string back. I'm like,
-
8:04 - 8:07okay, gives me a little bit of inspiration that it made one recursive call, right, and then hit
-
8:07 - 8:09the base case on the subsequent one.
-
8:09 - 8:12Now I start doing better ones. A and B,
-
8:12 - 8:16and I'm seeing A B B A. Okay, so I feel like, you know, I got this, so if I put a C in
-
8:16 - 8:17the front,
-
8:17 - 8:20and I put the B A behind,
-
8:20 - 8:21then hopefully what I believe is that
-
8:21 - 8:24it's gonna try, you know, C in the front, and then it's gonna permute A and B
-
8:24 - 8:27behind it, and then similarly on down.
-
8:27 - 8:30So some simple cases that I can see
-
8:30 - 8:34verifying that it does produce, kind of, the input string as itself, and then it does the
-
8:34 - 8:37back end rearrangement, leaving this in the front, and then it makes the next choice for what can
-
8:37 - 8:40go in the front, and then the back end rearrangement. And kind of seeing the
-
8:40 - 8:44pattern that matches my belief about how the code works, right,
-
8:44 - 8:45helps me to feel good. What happens if I
-
8:45 - 8:48put in
-
8:48 - 8:50something that has double letters in it?
-
8:50 - 8:53So I put A P P L E in there.
-
8:53 - 8:56And all the way back at the beginning, right, I can
-
8:56 - 8:58plot more of them, right, that grows quite
-
8:58 - 9:02quickly right as we add more and more letters, right? Seeing the apple, appel,
-
9:02 - 9:02and stuff like that.
-
9:02 - 9:05There's a point where it starts picking the P to go in the front,
-
9:05 - 9:10and the code as it's written, right, doesn't actually make it a combination for this P
-
9:10 - 9:11and this P really being different.
-
9:11 - 9:13So it goes through a whole sequence of
-
9:13 - 9:17pull the second character to the front, and then permute the remaining four.
-
9:17 - 9:20And then it says, and now pull the third character to the front and permute
-
9:20 - 9:22the remaining four, which turns out to be exactly the same thing. So there should be
-
9:22 - 9:25this whole sequence in the middle, right,
-
9:25 - 9:27of the same Ps
-
9:27 - 9:29repeated twice
-
9:29 - 9:31because we haven't gone over a way to do anything about that, right?
-
9:31 - 9:33So
-
9:33 - 9:36-but it is reassuring to know that it did somehow didn't get, you know, confused by the idea of
-
9:36 - 9:38there being two double letters. [Inaudible] if I do this -if I just say A
-
9:38 - 9:41B A, right?
-
9:41 - 9:44Something a little bit smaller to look at, right?
-
9:44 - 9:47A in the front. A in the front goes permuted, B in the front, and then it ends up permuting
-
9:47 - 9:50these two ways that ends up being exactly the same, and then I get a duplicate of those in
-
9:50 - 9:51the front.
-
9:51 - 9:53So right now, it doesn't know that there's anything to worry about in terms
-
9:53 - 9:55of duplicates?
-
9:55 - 9:57What's a really easy way to get rid of duplicates?
-
9:57 - 9:59Don't think recursively, think -use a set.
-
9:59 - 10:01Right? I could just stuff them in a set, right?
-
10:01 - 10:04And then if it comes across the same one again it's like, yeah,
-
10:04 - 10:07whatever. So it would still do the extra work of finding those down,
-
10:07 - 10:11but would actually, like, I could print the set at the end having coalesced any of the duplicates.
-
10:11 - 10:13To
-
10:13 - 10:15actually change it in the code,
-
10:15 - 10:18it's actually not that hard either.
-
10:18 - 10:19The idea here is that
-
10:19 - 10:21for all of the characters that remain, right,
-
10:21 - 10:25and sometimes what I want to choose from is of the remaining characters
-
10:25 - 10:25uniqued,
-
10:25 - 10:27right? Pick one to move to the front.
-
10:27 - 10:29So if there's three more Ps
-
10:29 - 10:31that remain in rest,
-
10:31 - 10:34I don't need to try each of those Ps individually in the front, right? They'll produce
-
10:34 - 10:37the same result -pulling one and leaving the other two behind
-
10:37 - 10:39is completely irrelevant.
-
10:39 - 10:42So an easy way to actually stop it from even generating them,
-
10:42 - 10:46is when looking at the character here is to make sure that it is -that it
-
10:46 - 10:50doesn't duplicate anything else in the rest. And so
-
10:50 - 10:53probably the easiest way to do that is to either pick the first of the Ps or the last
-
10:53 - 10:57of the Ps, right, and to recur on and ignore the other ones.
-
10:57 - 11:00So, for example, if right here I did a find on the rest
-
11:00 - 11:02after I -do you see any more of these?
-
11:02 - 11:04And if you do,
-
11:04 - 11:07then skip it and just let those go. Or, you know,
-
11:07 - 11:10do the first. Don't do the remaining ones. You can either look to the left of look to the
-
11:10 - 11:13right and see if you see any more, and if so,
-
11:13 - 11:14skip the,
-
11:14 - 11:19you know, early or later ones depending on what your strategy is.
-
11:19 - 11:25Any questions about permute here? [Inaudible].
-
11:25 - 11:27So the [inaudible] can be just -look down here, right, it just looks like that, right?
-
11:27 - 11:31This is a very common thing. You'll see this again, and again, and it tends to be that the
-
11:31 - 11:33outer call, right, it tends to have this sort of
-
11:33 - 11:34this, you know, solve this problem,
-
11:34 - 11:37and then it turns out during the recursive calls you need to maintain some state
-
11:37 - 11:40about where you are in the problem. You know, like, how many letters you moved, or
-
11:40 - 11:44what permutation you've built so far, or where you are in the maze, or whatever it is you're
-
11:44 - 11:45trying to solve.
-
11:45 - 11:49And so typically that wrapper call is just gonna be setting up the initial call in a
-
11:49 - 11:52way that has the initial form of that state
-
11:52 - 11:52present
-
11:52 - 11:56that the client to the function didn't need to know about. It's just our own housekeeping that we're
-
11:56 - 11:58setting up.
-
11:58 - 12:01Seems almost kind of silly to write down the function that has just line that just turns it
-
12:01 - 12:04into, basically, it's just exchanging
-
12:04 - 12:06-setting up the
-
12:06 - 12:11other parameters.
-
12:11 - 12:13I
-
12:13 - 12:17am going to show you the other kind of master patter, and
-
12:17 - 12:20then we're gonna go on to kind of use them to solve other problems.
-
12:20 - 12:24This is the one that was already alluded to, this idea of a combinations. Instead
-
12:24 - 12:26of actually producing all of the four character strings that involve
-
12:26 - 12:28rearrangements of A B C D,
-
12:28 - 12:32what if I were to [inaudible] in kind of the subgroups, or the way I could chose certain
-
12:32 - 12:34characters out of that
-
12:34 - 12:35initial input, and
-
12:35 - 12:39potentially exclude some, potentially include some? So if I have A B C,
-
12:39 - 12:41then the subsets of the subgroups of that
-
12:41 - 12:45would be the single characters A B and C. The empty string A B and C itself the
-
12:45 - 12:50full one, and then the combinations of two, A B, A C, and B C.
-
12:50 - 12:53Now, in this case we're gonna say that order doesn't matter. We're not -whereas permutations was all
-
12:53 - 12:54about order, I'm
-
12:54 - 12:57gonna use -I'm gonna structure this one where I don't care. If it's A B or
-
12:57 - 12:59B A I'm gonna consider it the same subset.
-
12:59 - 13:05So I'm just interested in inclusion. Is A in or out? Is B in or out? Is C in or out?
-
13:05 - 13:09And so the recursive strategy we're gonna take is exactly what I have just
-
13:09 - 13:12kind of alluded to in my English description there,
-
13:12 - 13:15is that I've got an input, A B C.
-
13:15 - 13:18Each of those elements has either the opportunity of being in the subset or
-
13:18 - 13:19not.
-
13:19 - 13:21And I need to make that decision for everyone
-
13:21 - 13:25-every single element, and then I need to kind of explore all the possible
-
13:25 - 13:26combinations of that, right?
-
13:26 - 13:29When A is in, what if B is out? When A is in, what if B is in?
-
13:29 - 13:32So the recursion that I'm gonna use here
-
13:32 - 13:35is that at each step of the way, I'm gonna separate one element from the
-
13:35 - 13:36input,
-
13:36 - 13:39and probably the easiest way to do that is just to kind of take the front
-
13:39 - 13:40most element off the input
-
13:40 - 13:42and sort of
-
13:42 - 13:45separate it into this character by itself and then the remainder. Similarly, the way
-
13:45 - 13:46I did with permute,
-
13:46 - 13:49and then given that element I have
-
13:49 - 13:51earmarked here, I can
-
13:51 - 13:54try putting it in the current subset or not. I need to try both, so I'm gonna make
-
13:54 - 13:56two recursive calls here,
-
13:56 - 13:58one recursive call where I've added it in,
-
13:58 - 14:02one recursive call where I haven't added it in. In both cases, right, I will have
-
14:02 - 14:04removed it from the rest,
-
14:04 - 14:08so what's being chosen from to complete that subset
-
14:08 - 14:10always is a little bit smaller, a little bit easier.
-
14:10 - 14:14So this is very, very much like the problem I described as the chose
-
14:14 - 14:18problem. Trying to choose four people from a dorm to go to flicks was
-
14:18 - 14:19picking Bob
-
14:19 - 14:21and then -[inaudible] to Bob and not Bob, and then
-
14:21 - 14:25saying, well, Bob could go, in which I need to pick three people to go with him,
-
14:25 - 14:29or Bob could not go and I need to pick four people to go without Bob.
-
14:29 - 14:34This is very much that same pattern. Two recursive calls. Identify one in or out.
-
14:34 - 14:36The base case becomes when there's nothing left
-
14:36 - 14:39to check out.
-
14:39 - 14:41So I start with the input A B C -A
-
14:41 - 14:42B C D let's say.
-
14:42 - 14:45I look at that first element -I just need to pick one. Might as well pick the front one, it's the
-
14:45 - 14:47easy one to get to.
-
14:47 - 14:48I add it to the subset,
-
14:48 - 14:52remove it from the input, and make a recursive call.
-
14:52 - 14:54When that recursion completely terminates,
-
14:54 - 14:56I get back to this call,
-
14:56 - 14:58and I do the same thing again.
-
14:58 - 15:02Remaining input is B C D again but now the subset that I've been building doesn't
-
15:02 - 15:03include.
-
15:03 - 15:05So inclusion exclusion
-
15:05 - 15:13are the two things that I'm trying. So the
-
15:13 - 15:16subset problem, right, very similar in structure to the way that I set
-
15:16 - 15:20up permutations, right, as I'm gonna keep track of two strings as I'm working my way
-
15:20 - 15:20down
-
15:20 - 15:24the remainder in the rest, right, things that I haven't yet explored
-
15:24 - 15:28so far is what characters I've chosen to place into the subset that I'm building.
-
15:28 - 15:32If I get to the end where there's nothing left in the rest, so there's no
-
15:32 - 15:33more choices to make,
-
15:33 - 15:37then what I have in the subset is what I have in the subset, and I go ahead and print it.
-
15:37 - 15:38In the case that there's still something to look at
-
15:38 - 15:41I make these two calls,
-
15:41 - 15:44one where I've appended it in, where I haven't, and then both cases, right, where I
-
15:44 - 15:47have subtracted it off of the
-
15:47 - 15:49rest by using the subster to
-
15:49 - 15:55truncate that front character off.
-
15:55 - 15:56So the way that
-
15:56 - 15:57permute was making calls, right, was in a loop,
-
15:57 - 16:00and so sometimes it's a little bit misleading. You look at it and you think there's
-
16:00 - 16:03only one recursive call, but in fact it's in inside a loop, and so it's making,
-
16:03 - 16:06potentially, end recursive calls where end is the length of
-
16:06 - 16:08the input.
-
16:08 - 16:10It gets a little bit shorter each time through but there's always, you know, however many
-
16:10 - 16:13characters are in rest is how many recursive calls it makes.
-
16:13 - 16:17The subsets code actually makes exactly two recursive calls at any given stage, in or out,
-
16:17 - 16:21and then recurs on that and what is one remaining.
-
16:21 - 16:23It also needs a wrapper
-
16:23 - 16:26for the same exact reason that permutations did. It's
-
16:26 - 16:28just that we are trying to
-
16:28 - 16:29
-
16:29 - 16:32list the subsets of a particular string, in fact, there's some housekeeping that's going along
-
16:32 - 16:36with it. We're just trying the subset so far is something we don't necessarily
-
16:36 - 16:38want to put into the public interface in the way that somebody would have to
-
16:38 - 16:44know what to pass to that to get the right thing. Anybody have
-
16:44 - 16:48a question about this?
-
16:48 - 16:50So given the way this code is written,
-
16:50 - 17:05what is the first subset that is printed if I give it the input A B C D?
-
17:05 - 17:07A B C D. Just like it was with permute, right? Everything went in.
-
17:07 - 17:19What is the second one printed after that?
-
17:19 - 17:20A B C, right? So I'm
-
17:20 - 17:22gonna look at my little diagram with you
-
17:22 - 17:27to help kind of trace this process of the recursive call, right, is that
-
17:27 - 17:31the leftmost arm is the inclusion arm, the right arm is the exclusion arm.
-
17:31 - 17:34At every level of the tree, right, we're looking at the next character of
-
17:34 - 17:36the rest and deciding whether to go in or out,
-
17:36 - 17:38the first call it makes is always in,
-
17:38 - 17:41so at the beginning it says, I'm choosing about A. Is A in? Sure.
-
17:41 - 17:44And then it gets back to the level of recursion. It says, okay, look at the first
-
17:44 - 17:48thing of rest, that's B. Is B in? Sure. Goes down the right arm, right?
-
17:48 - 17:52Is C in? Sure. Is D in? Sure. It gets to here and now we have nothing left, so we
-
17:52 - 17:54have [inaudible] A B C D.
-
17:54 - 17:58With the rest being empty, we go ahead and print it [inaudible] there's no more choices to
-
17:58 - 18:01make. We've looked at every letter and decided whether it was in or out.
-
18:01 - 18:05It will come back to here, and I'll say, okay, I've finished all the things I can make
-
18:05 - 18:06with D in,
-
18:06 - 18:09how about we try it with D out. And so then D out
-
18:09 - 18:11gives us just the A B C.
-
18:11 - 18:13After it's done everything it can do with
-
18:13 - 18:17A B C in, it comes back to here and says, okay, well now do this arm,
-
18:17 - 18:21and this will drop C off, and then try D in, D out.
-
18:21 - 18:25And so it will go from the biggest sets to the smaller sets, not quite
-
18:25 - 18:26monotonically though.
-
18:26 - 18:28The very last set printed will be the empty set,
-
18:28 - 18:31and that will be the one where it was excluded all the way down, which after it kind of tried
-
18:31 - 18:34all these combinations of in out, in out, in out, it
-
18:34 - 18:37eventually got to the out, out, out, out, out, out, out case which will give me the
-
18:37 - 18:40empty set on that arm.
-
18:40 - 18:43Again, if I reverse the calls, right, I'd still see all the same subsets in
-
18:43 - 18:46the end. They just come out in a different order.
-
18:46 - 18:50But it is worthwhile to model the recursion in your own head to have this
-
18:50 - 18:54idea of understanding about how it goes deep, right? That
-
18:54 - 18:57it always makes that recursive call and has to work its way all the way to the
-
18:57 - 19:00base case and terminate that recursion before it will unfold
-
19:00 - 19:03and revisit the second call that was made, and
-
19:03 - 19:11then fully explore where it goes before it completes that whole sequence.
-
19:11 - 19:16Anybody want to ask me a question about these guys? These are
-
19:16 - 19:21just really, really important pieces of code, and so I'm trying to
-
19:21 - 19:25make sure that I don't move past something that still feels a little bit
-
19:25 - 19:27mystical or confusing to you because
-
19:27 - 19:29everything I want to do for the rest of today
-
19:29 - 19:30builds on this.
-
19:30 - 19:33So now if there's something about either of these pieces of code
-
19:33 - 19:38that would help you -yeah. What would
-
19:38 - 19:40be the simplest way to do that?
-
19:40 - 19:43So probably the simplest way, like, if you said, oh, I just really want it to be in alphabetical order,
-
19:43 - 19:45would be to put them in a set, right, and then
-
19:45 - 19:47have the set be the order for you. So you said
-
19:47 - 19:49order doesn't matter? Oh, you
-
19:49 - 19:53did care about how they got ordered. So, like, let's say you
-
19:53 - 19:57didn't want B C D to equal C D B.
-
19:57 - 20:00So in that case, right, you would be more likely to kind of add a permutation step into
-
20:00 - 20:04it, right? So if B C D was not the same thing as A B C, right, it would be, like,
-
20:04 - 20:05well
-
20:05 - 20:07I'm gonna chose -so in this case, right,
-
20:07 - 20:11it always -well the subsets will always be printed as kind of a subsequence. So -and let's
-
20:11 - 20:14say if the input was the alphabet, just easy way
-
20:14 - 20:15to describe it,
-
20:15 - 20:19all of the subsets I'm choosing will always be in alphabetical order because I'm always choosing A in or not, B in
-
20:19 - 20:19or not.
-
20:19 - 20:23If I really wanted B Z to be distinct from Z B,
-
20:23 - 20:27then really what I want to be doing at each step is picking the next character to go,
-
20:27 - 20:28
-
20:28 - 20:29and not
-
20:29 - 20:32always assuming the next one had to be the next one in sequence, so I would do more like a
-
20:32 - 20:36permute kind of loop that's like pick the next one that goes, remove it from what
-
20:36 - 20:38remains and recur,
-
20:38 - 20:40and that I need that separate step we talked about of -and
-
20:40 - 20:42in addition to kind of
-
20:42 - 20:43
-
20:43 - 20:45picking, we also have to
-
20:45 - 20:48leave open the opportunity that we didn't pick anything and we just kind of left the subject as is, right, so we
-
20:48 - 20:50could [inaudible] or not. And
-
20:50 - 20:54so permute always assumes we have to have picked everything. The subset code
-
20:54 - 20:57would also allow for
-
20:57 - 20:58some of them just being entirely skipped.
-
20:58 - 21:02So we pick the next one, right, and then eventually
-
21:02 - 21:04stopped picking.
-
21:04 - 21:07[Inaudible] just in your wrapper function
-
21:07 - 21:13then [inaudible] put a for loop or something like that, right? When you're through changing your string? Yeah, you can certainly do that, like in a permute from the outside too, right.
-
21:13 - 21:16So there's often very, you know,
-
21:16 - 21:19multiple different ways you can get it the same thing whether you want to put it in the recursion or
-
21:19 - 21:20outside the recursion,
-
21:20 - 21:22have the set help you do it or not,
-
21:22 - 21:26that can get you the same result.
-
21:26 - 21:28So let me try to
-
21:28 - 21:32identify what's the same about these to try to kind of back away from it and
-
21:32 - 21:33kind of
-
21:33 - 21:36move just to see how these are more similar than they are different, right,
-
21:36 - 21:40even though the code ends up kind of being -having some details in it
-
21:40 - 21:43that -if you kind of look at it from far away these are both problems that are
-
21:43 - 21:45about
-
21:45 - 21:45choice.
-
21:45 - 21:50That the recursive calls that we see have kind of a branching structure and a depth factor
-
21:50 - 21:53that actually relates to the problem if you think about it in terms of decisions,
-
21:53 - 21:57that in making a permutation your decision is what character goes next, right? In the
-
21:57 - 22:01subset it's like, well, whether this character goes in or not
-
22:01 - 22:05that the recursive tree that I was drawing that it shows all those calls,
-
22:05 - 22:09the depths of it represents the number of choices you make. Each
-
22:09 - 22:13recursive call makes a choice, right? A yes, no, or a next letter to go, and then recurs from
-
22:13 - 22:15there. So I make, you know,
-
22:15 - 22:18one of those calls, and then there's N minus 1 beneath it that represent
-
22:18 - 22:22the further decisions I make that builds on that. And so, in the case of permutation, once I've
-
22:22 - 22:23picked the, you
-
22:23 - 22:25know, N minus 1
-
22:25 - 22:29things to go, there's only one thing left, right? And so in some sense the tree is
-
22:29 - 22:31N because I have to pick N things that go in the permutation and then I'm
-
22:31 - 22:32done.
-
22:32 - 22:35In the subsets, it's also N, and that's because for each of the characters I'm deciding
-
22:35 - 22:37whether it's in or out. So I
-
22:37 - 22:40looked at A and decided in or out. I looked at B and decided in or out. And I did that all the
-
22:40 - 22:41way down.
-
22:41 - 22:42That was the life of the input.
-
22:42 - 22:44The branching
-
22:44 - 22:48represents how many recursive calls were made
-
22:48 - 22:52at each level of the recursion. In the case of subsets, it's always exactly two.
-
22:52 - 22:54In, out, all the way down,
-
22:54 - 22:59restarts at 1, branches to 2, goes to 4, goes to 8, 16, and so on.
-
22:59 - 23:01In the permute case, right,
-
23:01 - 23:05there are N calls at the beginning. I have N different letters to choose from, so
-
23:05 - 23:10it's a very wide spread there, and that at that next level, it's N minus 1.
-
23:10 - 23:12Still very wide. And N minus 2. And
-
23:12 - 23:16so the overall tree has kind of an N times N minus 1 times N minus
-
23:16 - 23:192 all the way down to the bottom, which the factorial function
-
23:19 - 23:22-which grows very, very quickly.
-
23:22 - 23:26Even for small inputs, right, the number of permutations is enormous.
-
23:26 - 23:28The number of subsets is to the end
-
23:28 - 23:29
-
23:29 - 23:30in or out, right, all the way across.
-
23:30 - 23:32Also, a very,
-
23:32 - 23:34you know,
-
23:34 - 23:37resource intensive problem to solve, not nearly as bad as permutation, but both of
-
23:37 - 23:41them, even for small sizes of N, start to become pretty quickly intractable.
-
23:41 - 23:44This is not the fault of recursion, right, these problems are not hard to solve because
-
23:44 - 23:48we're solving them in the wrong way. It's because there are N factorial permutations. There are
-
23:48 - 23:49[inaudible] different subsets,
-
23:49 - 23:52right? Anything that's going to print to the N things, or N factorial things is going
-
23:52 - 23:56to do N factorial work to do so. You can't avoid it.
-
23:56 - 23:59There's a big amount of work to be done in there.
-
23:59 - 24:02But what we're trying to look at here is this idea that those trees, right,
-
24:02 - 24:04represent decisions.
-
24:04 - 24:08There's some decisions that are made, you know, a decision is made at each level of recursion,
-
24:08 - 24:09which then
-
24:09 - 24:11is kind of a little bit closer
-
24:11 - 24:14to having no more decisions to make. You have so many decisions to make, which is
-
24:14 - 24:18the depth of the recursion. Once you've made all those decisions, you hit your base case
-
24:18 - 24:19and you're done. The
-
24:19 - 24:23tree being very wide and very deep makes for expensive exploration.
-
24:23 - 24:27What we're gonna look at is a way that we can take the same structure of the
-
24:27 - 24:31problem, one that fundamentally could be exhaustive, exhaustive meaning tried every
-
24:31 - 24:35possible combination, every possible rearrangement and option,
-
24:35 - 24:38and only explore some part of the tree.
-
24:38 - 24:41So only look around in some region,
-
24:41 - 24:43and as soon as we find something that's good enough.
-
24:43 - 24:46So in the case, for example, of a search problem, it might be that we're searching
-
24:46 - 24:50this space that could potentially cause us to look at every option,
-
24:50 - 24:54but we're also willing to say if we make some decisions that turn out good enough,
-
24:54 - 24:57that get us to our goal, or whatever it is we're looking for,
-
24:57 - 25:00we won't have to keep working any farther. So I'm gonna show
-
25:00 - 25:03you how we can take an exhaustive recursion problem and turn it into
-
25:03 - 25:06what's called a recursive backtracker. So
-
25:06 - 25:07there's
-
25:07 - 25:10a lot of text on this slide but let me just tell you in English what we're trying to
-
25:10 - 25:12get at.
-
25:12 - 25:13That
-
25:13 - 25:14
-
25:14 - 25:17the idea behind permutations or subsets is that at every level there's all
-
25:17 - 25:20these choices and we're gonna try every single one of them.
-
25:20 - 25:25Now imagine we were gonna make a little bit less a guarantee about that.
-
25:25 - 25:26Let's design the function
-
25:26 - 25:30to return some sort of state that's like I succeeded or I failed. Did
-
25:30 - 25:33I find what I was looking for?
-
25:33 - 25:33
-
25:33 - 25:38At each call, I still have the possibility of multiple calls of in out, or a choice
-
25:38 - 25:40from what's there.
-
25:40 - 25:42I'm gonna go ahead and make the choice,
-
25:42 - 25:44make the recursive call,
-
25:44 - 25:47and then catch the result from that recursive call, and see whether it
-
25:47 - 25:51succeeded. Was that a good choice? Did that choice get me to where I wanted to be?
-
25:51 - 25:52If it did,
-
25:52 - 25:53then I'm done.
-
25:53 - 25:56I won't try anything else. So I'll stop early,
-
25:56 - 25:59quite going around the for loop, quit making other recursive calls,
-
25:59 - 26:02and just immediately [inaudible] say I'm done.
-
26:02 - 26:03If it didn't
-
26:03 - 26:07-it came back with a failure, some sort of code that said it didn't get where I
-
26:07 - 26:10want to do, then I'll try a different choice.
-
26:10 - 26:14And, again, I'll be optimistic. It's a very optimistic way of doing stuff. It says
-
26:14 - 26:17make a choice, assume it's a good one, and go with it.
-
26:17 - 26:19Only when you learn it didn't work out
-
26:19 - 26:23do you revisit that decision and back up and try again.
-
26:23 - 26:27So let me show you the code. I think it's gonna make more sense, actually, if
-
26:27 - 26:28I
-
26:28 - 26:30do it in terms of looking at what the code looks like.
-
26:30 - 26:35This is the pseudo code at which all recursive backtrackers at their heart
-
26:35 - 26:37come down to this pattern.
-
26:37 - 26:41So what I -I tried to be abstract [inaudible] so what does it mean to solve a
-
26:41 - 26:44problem, and what's the configuration? That depends on the domain and the problem
-
26:44 - 26:45we're trying to solve.
-
26:45 - 26:48But the structure of them all looks the same in that sense that
-
26:48 - 26:53if there are choices to be made -so the idea is that we cast the problem as a decision
-
26:53 - 26:54problem.
-
26:54 - 26:56There are a bunch of choices to be made.
-
26:56 - 26:58Each [inaudible] will make one choice
-
26:58 - 27:00and then attempt to recursively solve it. So
-
27:00 - 27:04there's some available choices, in or out, or one of next, or where to place a
-
27:04 - 27:07tile on a board, or whether to take a left or right turn and go straight in a
-
27:07 - 27:10maze. Any of these things could be the choices here.
-
27:10 - 27:11We make a choice,
-
27:11 - 27:13we feel good about it, we commit to it,
-
27:13 - 27:16and we say, well, if we can solve from here -so we kind of update our statement so we've made
-
27:16 - 27:19that term, or,
-
27:19 - 27:21you know, chosen that letter, whatever it is we're doing.
-
27:21 - 27:24If that recursive call returned true
-
27:24 - 27:25then we return true,
-
27:25 - 27:28so we don't do any unwinding. We don't try all the other choices. We stop that for
-
27:28 - 27:29loop early.
-
27:29 - 27:32We say that worked. That was good enough.
-
27:32 - 27:35If the solve came back with a negative result,
-
27:35 - 27:36that causes us to unmake that choice,
-
27:36 - 27:39and then we come back around here and we try another one.
-
27:39 - 27:42Again, we're optimistic. Okay, left didn't work, go straight.
-
27:42 - 27:46If straight doesn't work, okay, go right. If right didn't work and we don't have any
-
27:46 - 27:50more choices, then we return false, and
-
27:50 - 27:55this false is the one that then causes some earlier decision to get unmade
-
27:55 - 28:00which allows us to revisit some earlier optimistic choice, undo it, and
-
28:00 - 28:01try again.
-
28:01 - 28:04The base case is hit when we run out of choices
-
28:04 - 28:08where we've -whatever configuration we're at is, like, okay, we're at a dead end, or we're at
-
28:08 - 28:10the goal, or we've
-
28:10 - 28:14run out of letters to try. Whatever it is, right, that tells us, okay, we didn't
-
28:14 - 28:17-there's nothing more to decide. Is this where we wanted to be?
-
28:17 - 28:18Did it solve the problem?
-
28:18 - 28:23And I'm being kind of very deliberate today about what does it mean [inaudible] update the configuration, or what does it
-
28:23 - 28:25mean for it to be the goal state because for different problems it definitely means different
-
28:25 - 28:29things. But the code for them all looks the same
-
28:29 - 28:30kind of in
-
28:30 - 28:33its skeletal form.
-
28:33 - 28:38So let me take a piece of code and turn it into a recursive backtracker with you.
-
28:38 - 28:40So I've got recursive permute up
-
28:40 - 28:44here. So as it is, recursive permute tries every possible permutation, prints them all.
-
28:44 - 28:47What I'm interested in is is
-
28:47 - 28:51this sequence a letters an anagram. Meaning, it is -can be rearranged into
-
28:51 - 28:54something that's an English word. Okay.
-
28:54 - 28:56So what I'm gonna do is I'm gonna go in and edit it. The
-
28:56 - 28:59first thing I'm gonna do is I'm gonna change it to where it's gonna return some
-
28:59 - 29:00information.
-
29:00 - 29:08That information's gonna be yes it works, no it didn't. Okay? Now I'm gonna do this.
-
29:08 - 29:10I'm
-
29:10 - 29:13gonna
-
29:13 - 29:17add a parameter to this because I -in order to tell that it's a word I have to
-
29:17 - 29:19have someplace to look it up. I'm gonna use the lexicon that actually we're using on this
-
29:19 - 29:22assignment.
-
29:22 - 29:24And so
-
29:24 - 29:26when I get to the bottom
-
29:26 - 29:30and I have no more choices, I've got some permutation I've assembled here in -so
-
29:30 - 29:31far.
-
29:31 - 29:35And I'm going to check and see if it's in the dictionary.
-
29:35 - 29:38If the dictionary says that that's a word then
-
29:38 - 29:41I'm gonna say this was good. That permutation was good.
-
29:41 - 29:44You don't need to look at any more permutations. Otherwise I'll return false which will
-
29:44 - 29:46say, well, this thing isn't a word. Why don't you try again?
-
29:46 - 29:48I'm gonna
-
29:48 - 29:53change the name of the function while I'm at it to be a little more descriptive, and we'll call it is anagram.
-
29:53 - 29:58And then when I make the call here [inaudible]
-
29:58 - 30:00third argument.
-
30:00 - 30:03I'm not just gonna make the call and let it go away. I really want to know did that
-
30:03 - 30:06work, so I'm gonna say, well, if
-
30:06 - 30:08it's an anagram
-
30:08 - 30:11then return true.
-
30:11 - 30:16So if given the choice I made -I've got these letters X J Q P A B C,
-
30:16 - 30:16right?
-
30:16 - 30:20It'll pick a letter and it'll say, well if, you know, put that letter in the front
-
30:20 - 30:23and then go for it. If you can make a word out of having made that
-
30:23 - 30:26choice, out of what remains, then you're done. You don't need to try anything else. Otherwise
-
30:26 - 30:29we'll come back around and make some of the further calls in that loop
-
30:29 - 30:32to see if it worked out.
-
30:32 - 30:34At the bottom, I also need
-
30:34 - 30:36another failure case here,
-
30:36 - 30:38and that comes when
-
30:38 - 30:43the earlier choices, right -so I got, let's say somebody has given me X J,
-
30:43 - 30:46and then it says, given X J, can you permute A and B to make a word? Well, it turns out
-
30:46 - 30:47that
-
30:47 - 30:50you can -you know this ahead of time. It doesn't have the same vision
-
30:50 - 30:54you do. But it says X J? A B? There's just nothing you can do but it'll try them all
-
30:54 - 30:57dutifully. Tried A in the front and then B behind, and then tried B in the front and A behind it, and
-
30:57 - 31:01after it says that, it says, you know what, okay, that just isn't working, right?
-
31:01 - 31:02It must be some
-
31:02 - 31:05earlier decision that was really at fault.
-
31:05 - 31:08This returned false is going to cause
-
31:08 - 31:09the, you
-
31:09 - 31:13know, sort of stacked up previous anagram calls to say, oh yeah, that
-
31:13 - 31:16choice of X for the first letter was really
-
31:16 - 31:19questionable. So imagine I've had, like, E X, you know,
-
31:19 - 31:21T I. I'm trying to
-
31:21 - 31:24spell the word exit -is a possibility of it. That once I have that X in the
-
31:24 - 31:27front it turns out nothing is going to work out, but it's gonna go through and try X
-
31:27 - 31:30E I T, X E T I, and so on.
-
31:30 - 31:33Well, after all those things have been tried it says, you know what, X in the front wasn't it,
-
31:33 - 31:37right? Let's try again with I in the front. Well after it does that it won't get anywhere either.
-
31:37 - 31:38Eventually it'll try E in the front
-
31:38 - 31:41and then it won't have to try anything else after that because that will eventually
-
31:41 - 31:44work out.
-
31:44 - 31:47So if I put this guy in like that,
-
31:47 - 31:49and I
-
31:49 - 31:59build myself a lexicon, and then
-
31:59 - 32:01I change this to
-
32:01 - 32:04
-
32:04 - 32:09anagram word. I
-
32:09 - 32:13can't spell. I'd better
-
32:13 - 32:16pass my lexicon because I'm gonna need that to
-
32:16 - 32:18do my word lookups.
-
32:18 - 32:20[Inaudible]. And down here.
-
32:20 - 32:23Whoops.
-
32:23 - 32:28Okay. I
-
32:28 - 32:33think
-
32:33 - 32:36that looks like it's okay. Well, no
-
32:36 - 32:43-finish this thing off here.
-
32:43 - 32:47And so if I type in, you know, a word that I know is a word to begin
-
32:47 - 32:47with,
-
32:47 - 32:49like
-
32:49 - 32:52boat, I happen to know the way the permutations work [inaudible] try that right away and find
-
32:52 - 32:52that.
-
32:52 - 32:56What if I get it toab, you know, which is a rearrangement of that, it eventually did find them.
-
32:56 - 32:59What if I give it something like this,
-
32:59 - 33:02which there's just no way you can get that in there. So it seems to [inaudible] it's
-
33:02 - 33:04not telling us where the word is. I can actually go and change it.
-
33:04 - 33:07Maybe that'd be a nice thing to say. Why don't I print the word
-
33:07 - 33:11when it finds it? If
-
33:11 - 33:14lex dot contains
-
33:14 - 33:16-words so far
-
33:16 - 33:20-then print it. That
-
33:20 - 33:25way I can find out what word it thinks it made out of it. So if I
-
33:25 - 33:27type toab -now
-
33:27 - 33:30look at that, bota. Who would know? That dictionary's full of some really ridiculous
-
33:30 - 33:33words.
-
33:33 - 33:37Now I'll get back with exit. Let's type some other words.
-
33:37 - 33:40Query. So it's finding some
-
33:40 - 33:44words, and then if I give it some word that I know is just nonsense
-
33:44 - 33:46it won't print anything
-
33:46 - 33:47[inaudible] false.
-
33:47 - 33:51And so in this case, what it's doing is its come to a partial exploration, right,
-
33:51 - 33:53of the permutation tree
-
33:53 - 33:55based on
-
33:55 - 34:00this notion of being able to stop early on success. So in the case of this one, right,
-
34:00 - 34:03even six nonsense characters, it really did do the full permutation, in this case,
-
34:03 - 34:06the six factorial permutations, and discover that none of them worked.
-
34:06 - 34:08But in the case of exit or the
-
34:08 - 34:10boat that,
-
34:10 - 34:13you know, early in the process it may have kind of made a decision, okay so [inaudible]
-
34:13 - 34:16in this case it will try all the permutations with Q in the front,
-
34:16 - 34:17right?
-
34:17 - 34:20Which means, okay, we'll go with it, and then it'll do them in order to start with, but it'll
-
34:20 - 34:23start kind of rearranging and jumbling them up, and eventually, right,
-
34:23 - 34:26it will find something that did work with putting in the front, and it will never unmake that
-
34:26 - 34:30decision about Q. It will just sort of have -made that decision early,
-
34:30 - 34:34committed to it, and worked out, and then it covers a whole space of the tree that never got
-
34:34 - 34:38explored of R in front, and Y in the front, and E in the front
-
34:38 - 34:40because it had a notion of
-
34:40 - 34:43what is a satisfactory outcome. So the base case that it finally got to in
-
34:43 - 34:47this case met the standard for being a word was all it wanted to find, so it just
-
34:47 - 34:49had to work through the base cases
-
34:49 - 34:50until it found one,
-
34:50 - 35:00and potentially that could be very few of them relative the huge space. All right.
-
35:00 - 35:02I have this code
-
35:02 - 35:05actually on this slide. So it's
-
35:05 - 35:08permute, and that is turning into is anagram. And so, in blue, trying to highlight
-
35:08 - 35:11the things that changed in the process, right, that
-
35:11 - 35:15the structure of kind of how it's exploring, and making the recursive calls is exactly
-
35:15 - 35:16the same.
-
35:16 - 35:19But what we're using now is some return information from the function to
-
35:19 - 35:22tell us how the progress went,
-
35:22 - 35:23and then
-
35:23 - 35:28having our base case return some sense of did we get where we wanted to be,
-
35:28 - 35:32and then when we make the recursive call, if it did succeed, right,
-
35:32 - 35:35we immediately return true and unwind out of the recursion,
-
35:35 - 35:37doing no further exploration,
-
35:37 - 35:40and in the case where all of our choices
-
35:40 - 35:41
-
35:41 - 35:45gave us no success, right, we will return the call that says, well that was unworkable how we got
-
35:45 - 35:49to where we were.
-
35:49 - 35:51So this is the transformation that
-
35:51 - 35:54you want to feel like you could actually sort of apply again and again, taking
-
35:54 - 35:58something that was exhaustive, and looked at a whole space,
-
35:58 - 36:01and then had -change it into a form where it's like, okay, well I wanted to stop
-
36:01 - 36:04early when I get to something that's good enough.
-
36:04 - 36:07A lot of problems, right, that are recursive backtrackers just end up being
-
36:07 - 36:08procedural code
-
36:08 - 36:11that got turned into this
-
36:11 - 36:15based on a goal that you wanted to get to being one of the possibilities of the
-
36:15 - 36:18exploration.
-
36:18 - 36:22Anybody have any questions of what we got there? Okay.
-
36:22 - 36:24I'm gonna show you some more
-
36:24 - 36:26just because they are
-
36:26 - 36:29-there are a million problems in this space, and the more of them you see, I
-
36:29 - 36:32think, the more the patterns will start to emerge.
-
36:32 - 36:35Each of these, right, we're gonna think of as decision problems, right, that we have some number
-
36:35 - 36:37of decisions to make,
-
36:37 - 36:39and we're gonna try to
-
36:39 - 36:42make a decision in each recursive call
-
36:42 - 36:45knowing that that gives us fewer decisions that we have to make in the
-
36:45 - 36:48smaller form of the sub problem that we've built that way,
-
36:48 - 36:51and then the decisions that we have open
-
36:51 - 36:53to us, the options there
-
36:53 - 36:56represent the different recursive calls we can make. Maybe it's a for loop, or
-
36:56 - 36:59maybe a list of the explicit alternatives that we have
-
36:59 - 37:03that will be open to us in any particular call.
-
37:03 - 37:06This is a CS kind of classic problem. It's one that, you know, it doesn't seem like
-
37:06 - 37:09it has a lot of utility but it's still interesting to think about, which is if
-
37:09 - 37:12you have an eight by eight chessboard, which is the standard chessboard size,
-
37:12 - 37:14and you had eight queen pieces,
-
37:14 - 37:18could you place those eight queens on the board
-
37:18 - 37:21in such a way that no queen is threatened by any other? The queen is
-
37:21 - 37:23the most powerful
-
37:23 - 37:24player on the board, right, can move
-
37:24 - 37:27any number of spaces horizontally, vertically, or diagonally on any
-
37:27 - 37:29straight line basically,
-
37:29 - 37:32and so it does seem like, you know, that there's a lot of contention on the
-
37:32 - 37:35board to get them all in there in such a way that they can't
-
37:35 - 37:37go after each other.
-
37:37 - 37:41And so if we think of this as a decision problem,
-
37:41 - 37:44each call's gonna make one decision and recur on the rest. The decisions we have to
-
37:44 - 37:45make are
-
37:45 - 37:50we need to place, you know, eight queens let's say, if the board is an eight by eight board.
-
37:50 - 37:54So at each call we could place one queen, leaving us with M minus 1 to
-
37:54 - 37:55go.
-
37:55 - 37:59The choices for that queen might be that one way to kind of
-
37:59 - 38:02keep our problem
-
38:02 - 38:04-just to manage the logistics of it is to say, well, we know that there's going to be a
-
38:04 - 38:07queen in each column,
-
38:07 - 38:08right,
-
38:08 - 38:10it certainly can't be that there's two in one column. So
-
38:10 - 38:13we can just do the problem column by column and say, well, the first thing we'll do is place
-
38:13 - 38:16a queen in the leftmost column.
-
38:16 - 38:18The next call will make a queen
-
38:18 - 38:21-place a queen in the column to the right of that, and then so on. So we'll work our way
-
38:21 - 38:23across the board from left to right,
-
38:23 - 38:25and then the choices for that queen
-
38:25 - 38:27will be any of the [inaudible]
-
38:27 - 38:32and some of those actually are -we may be able to easily eliminate as
-
38:32 - 38:35possibilities. So, for example, once this queen is down here in the bottommost row, and
-
38:35 - 38:40we move on to this next column, there's no reason to even try placing the queen
-
38:40 - 38:43right next to it because we can see that that immediately threatens.
-
38:43 - 38:46So what we'll try is, is there a spot in this column that
-
38:46 - 38:48works given the previous decisions I've made,
-
38:48 - 38:51and if so, make that decision and move on.
-
38:51 - 38:54And only if we learned that that decision, right,
-
38:54 - 39:00that we just made optimistically isn't successful will we back up and try again.
-
39:00 - 39:10So let me do a little demo with you.
-
39:10 - 39:12Kind of shows this
-
39:12 - 39:14doing its job.
-
39:14 - 39:17Okay.
-
39:17 - 39:20So [inaudible] I'm gonna do it as I said, kind of column by column.
-
39:20 - 39:24[Inaudible] is that I'm placing the queen in the leftmost column to begin, and the question
-
39:24 - 39:27mark here says this is a spot under consideration. I look at the
-
39:27 - 39:29configuration I'm in,
-
39:29 - 39:32and I say, is this a plausible place to put the queen?
-
39:32 - 39:34And there's no reason not to,
-
39:34 - 39:38so I go ahead and let the queen sit there.
-
39:38 - 39:42Okay, so now I'm going to make my second recursive call. I say I've placed one queen, now there's three
-
39:42 - 39:43more queens to go.
-
39:43 - 39:47Why don't we go ahead and place the queens that remain to the right of this. And so
-
39:47 - 39:50the next recursive call comes in and says, if you can place the queens given the
-
39:50 - 39:54decision I've already made, then tell me yes, and then I'll know all is good.
-
39:54 - 39:58So it looks at the bottommost row, and it says, oh, no, that won't work,
-
39:58 - 40:00right? There's a queen right there.
-
40:00 - 40:03It looks at the next one and then sees the diagonal attack. Okay. Moves up to
-
40:03 - 40:05here and says, okay, that's good.
-
40:05 - 40:06That'll work,
-
40:06 - 40:08right? Looks at all of them and it's okay.
-
40:08 - 40:12So now it says, okay, well I've made two decision. There's just two to go. I'm
-
40:12 - 40:16feeling good about it. Go ahead and make the recursive call.
-
40:16 - 40:19The third call comes in, looks at that row, not good,
-
40:19 - 40:21looks at that row, not good,
-
40:21 - 40:25looks at that row, not good, looks at that row, not good. Now this one -there weren't any
-
40:25 - 40:28options at all that were viable.
-
40:28 - 40:30We got here,
-
40:30 - 40:35and given the earlier decisions, and so the idea is that, given our optimism, right, we
-
40:35 - 40:39sort of made the calls and just sort of moved on. And now we've got in the situation where we
-
40:39 - 40:42have tried all the possibilities in this third recursive call and there was
-
40:42 - 40:46no way to make progress. It's gonna hit the return false at the bottom of the
-
40:46 - 40:47backtracking that says,
-
40:47 - 40:50you know what, there was some earlier problem.
-
40:50 - 40:50
-
40:50 - 40:54There was no way I could have solved it given the two choices -or, you know, whatever
-
40:54 - 40:56-we don't even know what choices were made, but there were some previous choices made, and
-
40:56 - 40:58given the state that was passed to this call,
-
40:58 - 41:01there's no way to solve it from here.
-
41:01 - 41:03And so this is gonna trigger the backtracking. So
-
41:03 - 41:06that backtracking is coming back to an earlier decision that you made and unmaking
-
41:06 - 41:07it.
-
41:07 - 41:12It's a return false coming out of that third call that then causes the second call to
-
41:12 - 41:13try again.
-
41:13 - 41:17And it goes up and it says okay, well where did I leave off? I tried the first couple of ones.
-
41:17 - 41:21Okay, let's try moving it up a notch and see how that goes.
-
41:21 - 41:22Then, again,
-
41:22 - 41:25optimistic, makes the call and goes for it.
-
41:25 - 41:28Can't do this one. That looks good.
-
41:28 - 41:31And now we're on our way to placing the last queen, feeling really comfortable and
-
41:31 - 41:33confidant,
-
41:33 - 41:34but
-
41:34 - 41:35discovering quickly,
-
41:35 - 41:39right, that there was no possible. So it turns out this configuration with these three
-
41:39 - 41:42queens, not solvable. Something must be wrong.
-
41:42 - 41:46Back up to the most immediate decision. She knows it doesn't unmake, you know,
-
41:46 - 41:50earlier decisions until it really has been proven that that can't work, so
-
41:50 - 41:52at this point it says, okay, well let's try finding
-
41:52 - 41:53something else in this
-
41:53 - 41:54column.
-
41:54 - 41:55No go.
-
41:55 - 41:58That says, okay, well that one failed so it must be that I made the wrong decision in
-
41:58 - 42:01the second column. Well, it turns out the second column -that was the last choice
-
42:01 - 42:05it had. So in fact it really was my first decision
-
42:05 - 42:08that got us off to the wrong foot.
-
42:08 - 42:11And now, having tried everything that there was possible, given the queen in the
-
42:11 - 42:14lower left in realizing none of them worked out, it comes back and says, okay, let's
-
42:14 - 42:18try again, and at this point it actually will go fairly quickly.
-
42:18 - 42:21Making that initial first decision
-
42:21 - 42:22was
-
42:22 - 42:24the magic that
-
42:24 - 42:26got it solved. And
-
42:26 - 42:30then we have a complete solution to the queens.
-
42:30 - 42:32We put it onto eight,
-
42:32 - 42:34and let it go.
-
42:34 - 42:38You can see it kind of checking the board, backing up, and you notice that it
-
42:38 - 42:42made that lower left decision kind of in -it's sticking to it, and so the idea is
-
42:42 - 42:46that it always backs up to the most recent decision point
-
42:46 - 42:47when it fails,
-
42:47 - 42:50and only after kind of that one has kind of tried all its options will it actually
-
42:50 - 42:54back up and consider a previous decision as being unworthy
-
42:54 - 43:01and revisiting it.
-
43:01 - 43:04In this case that first decision did work out,
-
43:04 - 43:06the queen being in the lower left.
-
43:06 - 43:09It turns out there were -you know, you saw the second one had to kind of slowly get
-
43:09 - 43:12inched up in the second row. Right? It wasn't gonna work with the third row. It tried
-
43:12 - 43:15that for a while. Tried the fourth row for a while.
-
43:15 - 43:18All the possibilities after that, but eventually it was that fifth row
-
43:18 - 43:22that then kind of gave it the breathing room to get those other queens out there.
-
43:22 - 43:25But it did not end up trying, for example, all the other positions for the queen in
-
43:25 - 43:30the first row, so it actually -it really looked at a much more constrained part of the entire
-
43:30 - 43:32search tree than
-
43:32 - 43:34an exhaustive recursion
-
43:34 - 43:39of the whole thing would have done.
-
43:39 - 43:46The code for that ?whoops
-
43:46 - 43:48-looks something like this.
-
43:48 - 43:49And
-
43:49 - 43:51one of the things that I'll strongly encourage you to do when you're writing
-
43:51 - 43:54a recursive backtracking routine,
-
43:54 - 43:58something I learned from Stuart Regis, who long ago was my mentor,
-
43:58 - 43:59was the idea that
-
43:59 - 44:03when -trying to make this code look as simple as possible, that one of the things
-
44:03 - 44:06you want to do is try to move away the details of the problem. For example,
-
44:06 - 44:08like, is safe
-
44:08 - 44:12-given the current placement of queens, and the row you're trying, and the column you're at,
-
44:12 - 44:15trying to decide that there's not some existing conflict on the board with the
-
44:15 - 44:19queen already being threatened by an existing queen just involves us
-
44:19 - 44:22kind of traipsing across the grid and looking at different things.
-
44:22 - 44:26But putting in its own helper function makes this code much easier to read, right?
-
44:26 - 44:28Similarly, placing the queen in the board, removing the queen from the board,
-
44:28 - 44:32there are things they need to do. Go up to state and draw some things on the
-
44:32 - 44:34graphical display.
-
44:34 - 44:37Put all that code somewhere else so you don't have to look at it, and then this
-
44:37 - 44:41algorithm can be very easy to read. It's like for all of the row. So given
-
44:41 - 44:44the column we're trying to place a queen in, we've got this grid
-
44:44 - 44:46of boolean that shows where the queens are so far,
-
44:46 - 44:50that for all of the rows across the board, if,
-
44:50 - 44:54right, it's safe to place a queen in that row and this column, then place the
-
44:54 - 44:56queen and see if you can solve
-
44:56 - 44:59starting from the column to the right, given this new update to the board. If it
-
44:59 - 45:03worked out, great, nothing more we need to do. Otherwise we need to take back that
-
45:03 - 45:05queen, unmake that decision,
-
45:05 - 45:06and try again.
-
45:06 - 45:09Try a higher row. Try a higher row, right.
-
45:09 - 45:13Again, assume it's gonna work out. If it does, great. If it doesn't, unmake it, try
-
45:13 - 45:16it again. If we tried all the rows that were open to us,
-
45:16 - 45:21and we never got to this case where this returned true, then we return false, which
-
45:21 - 45:22causes some
-
45:22 - 45:26previous one -we're backing up to a column behind it. So if we were currently trying to
-
45:26 - 45:27put a queen in column two,
-
45:27 - 45:31and we end up returning false, it's gonna cause column one to unmake a decision
-
45:31 - 45:33and move the queen up a little bit higher.
-
45:33 - 45:38If all of the options for column one fail, it'll back up to column zero.
-
45:38 - 45:41The base case here at the end, is if we ever get to where
-
45:41 - 45:45the column is past the number of columns on the board, then that means we placed a queen
-
45:45 - 45:47all the way across the board and
-
45:47 - 45:50we're in success land. So all
-
45:50 - 45:54this code kind of looks the same kind of standing back from it, right, it's
-
45:54 - 45:54like,
-
45:54 - 45:57for each choice, if you can make that choice, make it.
-
45:57 - 46:02If you solved it from here, great, otherwise, unmake that choice.
-
46:02 - 46:06Here's my return false when I ran out of options. There's my base case -it says
-
46:06 - 46:09if I have gotten to where there's no more decisions to make, I've placed all the
-
46:09 - 46:10queens,
-
46:10 - 46:14I've chosen all the letters, whatever, did I -am I where I wanted to be? There's no
-
46:14 - 46:17some sort of true or false analysis that comes out there about
-
46:17 - 46:21being in the right state. How do you feel
-
46:21 - 46:24about that? You guys look
-
46:24 - 46:24tired today, and
-
46:24 - 46:28I didn't even give you an assignment due today, so this can't be my fault,
-
46:28 - 46:30right?
-
46:30 - 46:33I got a couple more examples, and I'm probably actually just gonna go ahead and try to spend some time on
-
46:33 - 46:36them on Monday because I really don't want to -I
-
46:36 - 46:37want
-
46:37 - 46:38to
-
46:38 - 46:41give you a little bit more practice though. So we'll see. We'll see. I'll do at
-
46:41 - 46:44least one or two more of them on Monday before we start talking about pointers and linked lists, and so
-
46:44 - 47:00I will see you then. But having a good weekend. Come and hang out in Turbine with me.
- Title:
- Lecture 10 | Programming Abstractions (Stanford)
- Description:
-
Lecture 10 by Julie Zelenski for the Programming Abstractions Course (CS106B) in the Stanford Computer Science Department.
Julie explains procedural recursion and introduces permute code. She goes through another example of recursive code line by line, explaining each component. Recursive backtracking and it's usefulness are discussed. The example of placing several queen chess pieces on a board where none of them can attack the other is then demonstrated.
Complete Playlist for the Course:
http://www.youtube.com/view_play_list?p=FE6E58F856038C69CS 106B Course Website:
http://cs106b.stanford.eduStanford Center for Professional Development:
http://scpd.stanford.edu/Stanford University:
http://www.stanford.edu/Stanford University Channel on YouTube:
http://www.youtube.com/stanforduniversity/ - Video Language:
- English
- Duration:
- 47:02
N. Ueda edited English subtitles for Lecture 10 | Programming Abstractions (Stanford) | ||
N. Ueda edited English subtitles for Lecture 10 | Programming Abstractions (Stanford) | ||
Eunjeong_Kim added a translation |