WEBVTT

00:00:00.000 --> 00:00:01.924 align:middle line:90%
[SQUEAKING]

00:00:01.924 --> 00:00:04.329 align:middle line:90%
[RUSTLING]

00:00:04.329 --> 00:00:05.772 align:middle line:90%
[CLICKING]

00:00:05.772 --> 00:00:12.510 align:middle line:90%


00:00:12.510 --> 00:00:13.510 align:middle line:90%
ERIK DEMAINE: All right.

00:00:13.510 --> 00:00:18.080 align:middle line:84%
Welcome to practice
problem session 3, 006.

00:00:18.080 --> 00:00:20.600 align:middle line:84%
Today, we are going to go
through a bunch of problems,

00:00:20.600 --> 00:00:23.497 align:middle line:90%
which you should have already.

00:00:23.497 --> 00:00:25.580 align:middle line:84%
I was thinking of skipping
the very first problem,

00:00:25.580 --> 00:00:27.200 align:middle line:84%
because it's just
a mechanical thing.

00:00:27.200 --> 00:00:28.910 align:middle line:84%
If we have time at the end,
we can come back to it.

00:00:28.910 --> 00:00:31.310 align:middle line:84%
But there's not really any
insight I can give you in how

00:00:31.310 --> 00:00:32.352 align:middle line:90%
to approach this problem.

00:00:32.352 --> 00:00:34.220 align:middle line:84%
It's just, do you
understand hashing?

00:00:34.220 --> 00:00:36.470 align:middle line:84%
So I want to go into the
more creative problems first.

00:00:36.470 --> 00:00:41.010 align:middle line:84%
Let's start with problem
3.2, hash sequence.

00:00:41.010 --> 00:00:42.080 align:middle line:90%
So I'll just read it.

00:00:42.080 --> 00:00:46.070 align:middle line:84%
And then our first task is
to convert the word problem

00:00:46.070 --> 00:00:49.635 align:middle line:84%
into a concise formal algorithms
thing we need to achieve.

00:00:49.635 --> 00:00:52.010 align:middle line:84%
Then we need to come up with
ideas for how to achieve it.

00:00:52.010 --> 00:00:53.990 align:middle line:84%
And we need to
check the details.

00:00:53.990 --> 00:00:55.885 align:middle line:90%
That'll be our general pattern.

00:00:55.885 --> 00:00:57.260 align:middle line:84%
So this problem
says, hash tables

00:00:57.260 --> 00:00:59.210 align:middle line:84%
are not only useful for
implementing set operations,

00:00:59.210 --> 00:01:01.085 align:middle line:84%
they can also be used
to implement sequences.

00:01:01.085 --> 00:01:04.730 align:middle line:84%
Remember from lecture 2,
we have a set interface,

00:01:04.730 --> 00:01:07.370 align:middle line:84%
which is about querying
items by their key

00:01:07.370 --> 00:01:09.260 align:middle line:84%
and sort of intrinsic
order that's

00:01:09.260 --> 00:01:11.672 align:middle line:84%
about the items themselves,
versus a sequence

00:01:11.672 --> 00:01:13.880 align:middle line:84%
interface that we started
out with, with linked lists

00:01:13.880 --> 00:01:18.482 align:middle line:84%
and so on, and arrays,
where we're given an order,

00:01:18.482 --> 00:01:19.940 align:middle line:84%
and we want to
maintain that order.

00:01:19.940 --> 00:01:21.440 align:middle line:84%
And that order may
not have anything

00:01:21.440 --> 00:01:23.080 align:middle line:90%
to do with the items themselves.

00:01:23.080 --> 00:01:24.890 align:middle line:84%
So that's what we call
an extrinsic order.

00:01:24.890 --> 00:01:26.515 align:middle line:84%
We're told what the
order is by saying,

00:01:26.515 --> 00:01:29.240 align:middle line:84%
insert this item after this one,
or append this one to the end,

00:01:29.240 --> 00:01:31.620 align:middle line:90%
or prepend it to the beginning.

00:01:31.620 --> 00:01:36.830 align:middle line:84%
So in lecture last week, we
saw hash tables implement sets.

00:01:36.830 --> 00:01:43.470 align:middle line:84%
And let me just remind you
some things that they can do.

00:01:43.470 --> 00:01:47.460 align:middle line:84%
So we have, on the
one hand, set hashing.

00:01:47.460 --> 00:01:50.330 align:middle line:90%


00:01:50.330 --> 00:01:55.760 align:middle line:84%
So we're going to
need this in a moment.

00:01:55.760 --> 00:01:58.320 align:middle line:84%
This is just a
reminder from lecture.

00:01:58.320 --> 00:02:01.910 align:middle line:84%
We can build one in
linear time expected.

00:02:01.910 --> 00:02:06.530 align:middle line:84%
We can find an item in
constant timed expected by key.

00:02:06.530 --> 00:02:12.320 align:middle line:84%
And we can insert
or delete an item

00:02:12.320 --> 00:02:17.480 align:middle line:90%
in constant expected amortized.

00:02:17.480 --> 00:02:20.570 align:middle line:90%


00:02:20.570 --> 00:02:25.070 align:middle line:84%
OK, so this is a black
box that we're given.

00:02:25.070 --> 00:02:31.130 align:middle line:84%
And the problem statement
says that, imagine you're

00:02:31.130 --> 00:02:33.410 align:middle line:84%
given a hash table
as a black box, which

00:02:33.410 --> 00:02:37.160 align:middle line:84%
means we're giving a thing
that behaves just like a--

00:02:37.160 --> 00:02:39.530 align:middle line:90%
thank you, 2.

00:02:39.530 --> 00:02:41.870 align:middle line:84%
We're given something
that is a hash table.

00:02:41.870 --> 00:02:43.653 align:middle line:84%
But it's black box in
the sense we're not

00:02:43.653 --> 00:02:46.070 align:middle line:84%
allowed to reach in and change
the implementation details.

00:02:46.070 --> 00:02:49.190 align:middle line:84%
We're supposed to use it as is,
just by calling its interface.

00:02:49.190 --> 00:02:51.440 align:middle line:84%
So in particular, we're
giving these three operations.

00:02:51.440 --> 00:02:55.105 align:middle line:84%
I'll maybe also use iter to
iterate through the items.

00:02:55.105 --> 00:02:57.230 align:middle line:84%
So we're allowed to build
something in linear time,

00:02:57.230 --> 00:03:02.120 align:middle line:84%
find, and insert and delete in
constant expected amortized.

00:03:02.120 --> 00:03:03.920 align:middle line:84%
And what the
problem is asking is

00:03:03.920 --> 00:03:06.320 align:middle line:84%
to build out of
this data structure

00:03:06.320 --> 00:03:11.540 align:middle line:84%
a sequence with
particular time balance.

00:03:11.540 --> 00:03:17.000 align:middle line:84%
So this is what we call
a reduction in that we're

00:03:17.000 --> 00:03:19.700 align:middle line:90%
going to convert--

00:03:19.700 --> 00:03:22.820 align:middle line:84%
I guess technically, we're
reducing the sequence problem

00:03:22.820 --> 00:03:25.838 align:middle line:84%
to the set problem,
because we're

00:03:25.838 --> 00:03:28.130 align:middle line:84%
showing how to solve the
sequence problem using the set

00:03:28.130 --> 00:03:28.910 align:middle line:90%
problem.

00:03:28.910 --> 00:03:30.980 align:middle line:84%
But the way we'll think about
it is in the other direction.

00:03:30.980 --> 00:03:32.660 align:middle line:84%
We're given a data
structure that solves set.

00:03:32.660 --> 00:03:34.550 align:middle line:84%
And we're going to convert
it into a data structure that

00:03:34.550 --> 00:03:35.640 align:middle line:90%
solves sequence.

00:03:35.640 --> 00:03:38.580 align:middle line:84%
So given that we already know
how to do this from lecture,

00:03:38.580 --> 00:03:40.661 align:middle line:84%
we're going to learn
how to do this.

00:03:40.661 --> 00:03:43.945 align:middle line:84%
This is teaching you new
stuff in a problem set.

00:03:43.945 --> 00:03:45.320 align:middle line:84%
So the specific
bounds that we're

00:03:45.320 --> 00:03:51.020 align:middle line:84%
told to achieve are build
in constant expected time,

00:03:51.020 --> 00:04:00.290 align:middle line:84%
get and set_at in
constant expected time,

00:04:00.290 --> 00:04:12.770 align:middle line:84%
insert and delete_at in
linear expected time,

00:04:12.770 --> 00:04:23.930 align:middle line:84%
and insert and delete
first and last in--

00:04:23.930 --> 00:04:26.060 align:middle line:90%
we're running out of room here--

00:04:26.060 --> 00:04:31.550 align:middle line:90%
constant expected amortized.

00:04:31.550 --> 00:04:33.530 align:middle line:90%
OK.

00:04:33.530 --> 00:04:36.560 align:middle line:84%
So this is just what
we're told to do.

00:04:36.560 --> 00:04:38.730 align:middle line:90%
And now we start thinking.

00:04:38.730 --> 00:04:39.890 align:middle line:90%
So we're given this.

00:04:39.890 --> 00:04:42.500 align:middle line:90%
We want to build this.

00:04:42.500 --> 00:04:44.990 align:middle line:84%
And so I'm going to tell you
a little bit about my thought

00:04:44.990 --> 00:04:45.620 align:middle line:90%
process.

00:04:45.620 --> 00:04:47.453 align:middle line:84%
When I'm presented with
a problem like this,

00:04:47.453 --> 00:04:49.070 align:middle line:84%
the first thing is
to read the problem

00:04:49.070 --> 00:04:52.210 align:middle line:84%
and see, OK, what's
the hard part here?

00:04:52.210 --> 00:04:53.210 align:middle line:90%
What are the challenges?

00:04:53.210 --> 00:04:55.010 align:middle line:84%
So clearly, we
have to do all four

00:04:55.010 --> 00:04:56.480 align:middle line:90%
of these types of operations.

00:04:56.480 --> 00:04:59.060 align:middle line:84%
Build in linear expected time--
that's basically everything

00:04:59.060 --> 00:05:00.140 align:middle line:90%
we've seen.

00:05:00.140 --> 00:05:03.890 align:middle line:84%
Get or set_at in constant
expected time-- that's fast.

00:05:03.890 --> 00:05:07.400 align:middle line:84%
And that feels kind of
like this find operation.

00:05:07.400 --> 00:05:10.520 align:middle line:84%
So both of these seem
pretty matchy-matchy.

00:05:10.520 --> 00:05:12.770 align:middle line:84%
So that looks like
a good mapping.

00:05:12.770 --> 00:05:14.770 align:middle line:84%
I'm going to try to build
these operations using

00:05:14.770 --> 00:05:16.150 align:middle line:90%
those operations.

00:05:16.150 --> 00:05:20.260 align:middle line:84%
Insert and delete at
a specific location

00:05:20.260 --> 00:05:22.270 align:middle line:90%
in constant expected time--

00:05:22.270 --> 00:05:25.270 align:middle line:84%
sorry, linear expected
time-- that's big.

00:05:25.270 --> 00:05:28.540 align:middle line:84%
Linear expected time means I
can rebuild the entire data

00:05:28.540 --> 00:05:30.730 align:middle line:84%
structure every time
I do an operation.

00:05:30.730 --> 00:05:32.627 align:middle line:90%
So this is easy.

00:05:32.627 --> 00:05:34.210 align:middle line:84%
OK, that's the first
thing to realize.

00:05:34.210 --> 00:05:36.350 align:middle line:90%
This is big.

00:05:36.350 --> 00:05:36.850 align:middle line:90%
Great.

00:05:36.850 --> 00:05:39.160 align:middle line:84%
So I don't really have to
worry about these operations.

00:05:39.160 --> 00:05:40.780 align:middle line:84%
I mean, I do have
to implement them.

00:05:40.780 --> 00:05:46.480 align:middle line:84%
But it's not hard to do it that
fast, because I can rebuild.

00:05:46.480 --> 00:05:49.390 align:middle line:84%
And then here, insert and delete
at the beginning and the end

00:05:49.390 --> 00:05:52.300 align:middle line:84%
of the array, these are the DEQ,
Double-Ended Queue operations,

00:05:52.300 --> 00:05:54.520 align:middle line:84%
insert and delete at
either end, in constant

00:05:54.520 --> 00:05:55.780 align:middle line:90%
expected amortized time.

00:05:55.780 --> 00:05:58.970 align:middle line:84%
This, I feel like,
is a tricky one.

00:05:58.970 --> 00:06:01.510 align:middle line:84%
You've seen one way to
do this in a problem set.

00:06:01.510 --> 00:06:04.480 align:middle line:84%
But now we're going to
see another way with--

00:06:04.480 --> 00:06:08.800 align:middle line:84%
OK, the other thing to notice
is these "expected" words.

00:06:08.800 --> 00:06:10.780 align:middle line:84%
In this case, we're
told to use hashing.

00:06:10.780 --> 00:06:13.960 align:middle line:84%
But with lot of the problems,
you're not told how to solve it

00:06:13.960 --> 00:06:16.570 align:middle line:84%
or what you should be
basing your thing on.

00:06:16.570 --> 00:06:19.330 align:middle line:84%
And so "expected" is
always a good keyword,

00:06:19.330 --> 00:06:21.730 align:middle line:84%
because it means randomization
is involved somehow.

00:06:21.730 --> 00:06:24.460 align:middle line:84%
If you're told the bound
is going to be expected,

00:06:24.460 --> 00:06:28.030 align:middle line:84%
you probably need to
use randomization.

00:06:28.030 --> 00:06:30.830 align:middle line:84%
And in this class, the only form
of randomization you will use

00:06:30.830 --> 00:06:32.320 align:middle line:90%
is essentially hashing.

00:06:32.320 --> 00:06:35.645 align:middle line:90%
So that's a good hint.

00:06:35.645 --> 00:06:38.020 align:middle line:84%
In this case, we know what
we're supposed to use hashing.

00:06:38.020 --> 00:06:43.870 align:middle line:84%
All right, so this is
going to be the challenge.

00:06:43.870 --> 00:06:46.390 align:middle line:90%


00:06:46.390 --> 00:06:49.460 align:middle line:84%
But any ideas on how we
might tackle this problem?

00:06:49.460 --> 00:06:53.500 align:middle line:84%
How can we-- so set, remember,
every item has a key.

00:06:53.500 --> 00:06:55.823 align:middle line:84%
In a sequence, items
are just items.

00:06:55.823 --> 00:06:57.490 align:middle line:84%
And we're told to
insert and delete them

00:06:57.490 --> 00:06:59.110 align:middle line:90%
at particular locations.

00:06:59.110 --> 00:07:01.060 align:middle line:90%
But they don't have keys.

00:07:01.060 --> 00:07:02.440 align:middle line:84%
So one of the
challenges is going

00:07:02.440 --> 00:07:05.770 align:middle line:84%
to be to take our items
here, give them keys

00:07:05.770 --> 00:07:07.460 align:middle line:84%
so that we can
store them in a set.

00:07:07.460 --> 00:07:12.556 align:middle line:90%
Otherwise, we can't use find.

00:07:12.556 --> 00:07:14.700 align:middle line:84%
If there's no keys
there, there's

00:07:14.700 --> 00:07:15.700 align:middle line:90%
no way to search by key.

00:07:15.700 --> 00:07:18.100 align:middle line:90%


00:07:18.100 --> 00:07:18.600 align:middle line:90%
Ideas?

00:07:18.600 --> 00:07:23.870 align:middle line:90%


00:07:23.870 --> 00:07:27.830 align:middle line:84%
So let's think about
what we want to do.

00:07:27.830 --> 00:07:31.370 align:middle line:84%
Let's start with-- so
build, I think, is fine.

00:07:31.370 --> 00:07:33.370 align:middle line:84%
If you just want to
build a data structure,

00:07:33.370 --> 00:07:35.220 align:middle line:90%
you don't need to do anything.

00:07:35.220 --> 00:07:37.460 align:middle line:84%
The hard part are the
queries or updates

00:07:37.460 --> 00:07:39.870 align:middle line:84%
you want to be able to do
on your data structure.

00:07:39.870 --> 00:07:42.900 align:middle line:84%
Let's start with this
operation, get and set_at.

00:07:42.900 --> 00:07:46.280 align:middle line:84%
So remember, get_at,
you're given an index i,

00:07:46.280 --> 00:07:53.950 align:middle line:84%
and you want to find
the item at position i.

00:07:53.950 --> 00:07:58.190 align:middle line:84%
And set_at, we're
given a position,

00:07:58.190 --> 00:08:00.965 align:middle line:84%
and we want to change the
item stored at that position,

00:08:00.965 --> 00:08:03.210 align:middle line:90%
at that index, i.

00:08:03.210 --> 00:08:06.420 align:middle line:84%
Now, over here,
what we're given,

00:08:06.420 --> 00:08:07.850 align:middle line:90%
we can insert and delete.

00:08:07.850 --> 00:08:09.920 align:middle line:90%
But the main sort of lookup--

00:08:09.920 --> 00:08:11.870 align:middle line:90%
let's think about get_at first.

00:08:11.870 --> 00:08:16.170 align:middle line:84%
A natural mapping, given
this arrow, is find.

00:08:16.170 --> 00:08:19.500 align:middle line:84%
Find will search
for an item by key.

00:08:19.500 --> 00:08:21.750 align:middle line:84%
So here's-- just
staring at that,

00:08:21.750 --> 00:08:24.110 align:middle line:84%
let's look at all the possible
pairings you could do.

00:08:24.110 --> 00:08:25.760 align:middle line:90%
We have find by key over here.

00:08:25.760 --> 00:08:28.680 align:middle line:84%
And we need to implement
get_at by index.

00:08:28.680 --> 00:08:31.460 align:middle line:90%
So let's make the indices keys.

00:08:31.460 --> 00:08:35.390 align:middle line:90%
OK, so this is idea number one--

00:08:35.390 --> 00:08:47.870 align:middle line:84%
index-- assign a
key to each item

00:08:47.870 --> 00:08:51.495 align:middle line:90%
equal to index in sequence.

00:08:51.495 --> 00:08:55.790 align:middle line:90%


00:08:55.790 --> 00:08:58.580 align:middle line:90%
OK, so then, when I do--

00:08:58.580 --> 00:09:00.440 align:middle line:84%
to implement get_at,
I can just call

00:09:00.440 --> 00:09:06.380 align:middle line:90%
find of i if i is also a key.

00:09:06.380 --> 00:09:08.455 align:middle line:84%
And that should give me
the thing that I want.

00:09:08.455 --> 00:09:09.830 align:middle line:84%
Maybe for this to
make sense, let

00:09:09.830 --> 00:09:11.780 align:middle line:90%
me tell you how I'm building.

00:09:11.780 --> 00:09:16.820 align:middle line:84%
So if I'm given, say, an array
A of items, and they're both--

00:09:16.820 --> 00:09:18.910 align:middle line:84%
the only name conflict
here is build.

00:09:18.910 --> 00:09:21.620 align:middle line:84%
So let me call this
one sequence build.

00:09:21.620 --> 00:09:24.260 align:middle line:90%


00:09:24.260 --> 00:09:26.300 align:middle line:84%
And I'm going to implement
it using set build.

00:09:26.300 --> 00:09:29.600 align:middle line:90%


00:09:29.600 --> 00:09:32.930 align:middle line:84%
And I'll use some
shorthand notation here.

00:09:32.930 --> 00:09:35.870 align:middle line:84%
Let's say I want to
make an object that

00:09:35.870 --> 00:09:47.960 align:middle line:84%
has a key equal to i and
a value equal to A of i--

00:09:47.960 --> 00:09:50.090 align:middle line:90%
that's my object notation--

00:09:50.090 --> 00:09:58.100 align:middle line:84%
for i equals 0, 1, up
to size of A minus 1.

00:09:58.100 --> 00:10:02.040 align:middle line:84%
That's a little bit code-like,
but not quite literal code.

00:10:02.040 --> 00:10:03.750 align:middle line:84%
So I'm just going
to use this to say,

00:10:03.750 --> 00:10:07.863 align:middle line:84%
let's make an object
that has two parts.

00:10:07.863 --> 00:10:08.780 align:middle line:90%
One is called the key.

00:10:08.780 --> 00:10:11.840 align:middle line:84%
So we can talk about the
object.key, so we can--

00:10:11.840 --> 00:10:13.085 align:middle line:90%
which sets want to do.

00:10:13.085 --> 00:10:15.710 align:middle line:84%
And we're also going to store a
value, which is the actual item

00:10:15.710 --> 00:10:17.640 align:middle line:90%
that we're given.

00:10:17.640 --> 00:10:20.030 align:middle line:84%
So I'm just-- because these
are given in the sequence,

00:10:20.030 --> 00:10:21.738 align:middle line:84%
I'm just representing
that sequence order

00:10:21.738 --> 00:10:23.490 align:middle line:90%
by assigning i to be the key.

00:10:23.490 --> 00:10:26.240 align:middle line:84%
And so now, if I want to
find the item at index i,

00:10:26.240 --> 00:10:27.590 align:middle line:90%
I can do find of i.

00:10:27.590 --> 00:10:30.980 align:middle line:84%
And technically, I should
probably do .value.

00:10:30.980 --> 00:10:32.520 align:middle line:84%
That will give me
the actual item

00:10:32.520 --> 00:10:34.550 align:middle line:90%
that's stored at that position.

00:10:34.550 --> 00:10:37.580 align:middle line:84%
When I do find of i, I'm
going to get this whole object

00:10:37.580 --> 00:10:38.390 align:middle line:90%
with the key of i.

00:10:38.390 --> 00:10:41.720 align:middle line:84%
And then I want to get
the value part of it.

00:10:41.720 --> 00:10:45.500 align:middle line:84%
So then set_at, I
can just use this

00:10:45.500 --> 00:10:52.860 align:middle line:84%
find operation to get the
object and set its value to x.

00:10:52.860 --> 00:10:53.360 align:middle line:90%
Boom.

00:10:53.360 --> 00:10:57.050 align:middle line:84%
We've implemented array-like
semantics, get_at i

00:10:57.050 --> 00:11:01.130 align:middle line:90%
and set_at i, using a set.

00:11:01.130 --> 00:11:03.110 align:middle line:84%
If you've ever
programmed in JavaScript,

00:11:03.110 --> 00:11:05.750 align:middle line:84%
this should feel very familiar,
because JavaScript actually

00:11:05.750 --> 00:11:10.130 align:middle line:84%
implements arrays, at least
at the conceptual level,

00:11:10.130 --> 00:11:13.340 align:middle line:84%
as just general mapping
types, which are--

00:11:13.340 --> 00:11:16.820 align:middle line:84%
they call them objects, but
they are basically sets.

00:11:16.820 --> 00:11:18.290 align:middle line:90%
And it's even grosser.

00:11:18.290 --> 00:11:20.690 align:middle line:84%
They convert the integers
into strings and then

00:11:20.690 --> 00:11:24.815 align:middle line:84%
index everything by the
strings, semantically, anyway.

00:11:24.815 --> 00:11:26.690 align:middle line:84%
Implementation details
can be more efficient.

00:11:26.690 --> 00:11:28.860 align:middle line:84%
But conceptually,
that's what's going on.

00:11:28.860 --> 00:11:34.910 align:middle line:84%
And so that's the idea we're
doing here, which seems great.

00:11:34.910 --> 00:11:37.420 align:middle line:90%
Any problems?

00:11:37.420 --> 00:11:38.040 align:middle line:90%
So let's see.

00:11:38.040 --> 00:11:39.740 align:middle line:90%
There's insert_at and delete_at.

00:11:39.740 --> 00:11:41.420 align:middle line:84%
As I mentioned,
what I'm going to do

00:11:41.420 --> 00:11:44.650 align:middle line:84%
for those operations is just
rebuild the entire structure.

00:11:44.650 --> 00:11:46.715 align:middle line:90%
I'll just write that briefly.

00:11:46.715 --> 00:11:49.340 align:middle line:90%


00:11:49.340 --> 00:11:54.122 align:middle line:84%
Basically, let's just
iterate all the items.

00:11:54.122 --> 00:12:00.950 align:middle line:84%
Iterate all items, let's
say, into an array.

00:12:00.950 --> 00:12:04.670 align:middle line:90%
Insert, delete one of them.

00:12:04.670 --> 00:12:07.290 align:middle line:90%
And then rebuild.

00:12:07.290 --> 00:12:09.980 align:middle line:84%
OK, and if I was
writing a P set answer,

00:12:09.980 --> 00:12:11.480 align:middle line:84%
I would say a little
bit more detail

00:12:11.480 --> 00:12:14.482 align:middle line:90%
what I mean in this step.

00:12:14.482 --> 00:12:15.565 align:middle line:90%
I've done it in the notes.

00:12:15.565 --> 00:12:16.490 align:middle line:90%
Not that hard.

00:12:16.490 --> 00:12:18.320 align:middle line:84%
But we can afford
linear expected time.

00:12:18.320 --> 00:12:20.735 align:middle line:84%
I can afford to
call build again.

00:12:20.735 --> 00:12:22.110 align:middle line:84%
I guess, technically,
I'm calling

00:12:22.110 --> 00:12:23.970 align:middle line:90%
this build, sequence build.

00:12:23.970 --> 00:12:27.462 align:middle line:90%


00:12:27.462 --> 00:12:29.670 align:middle line:84%
So I can afford just to
extract things into an array,

00:12:29.670 --> 00:12:31.445 align:middle line:84%
do the linear time
operation on the array

00:12:31.445 --> 00:12:32.820 align:middle line:84%
with the shifting
and everything,

00:12:32.820 --> 00:12:34.205 align:middle line:90%
and then just call build again.

00:12:34.205 --> 00:12:34.830 align:middle line:90%
Yeah, question?

00:12:34.830 --> 00:12:36.648 align:middle line:84%
AUDIENCE: I had a
question about get_at.

00:12:36.648 --> 00:12:37.440 align:middle line:90%
ERIK DEMAINE: Yeah.

00:12:37.440 --> 00:12:41.340 align:middle line:90%
AUDIENCE: [INAUDIBLE] get_at.

00:12:41.340 --> 00:12:44.640 align:middle line:90%
ERIK DEMAINE: Sorry, no.

00:12:44.640 --> 00:12:46.800 align:middle line:84%
These are separate
definitions, yeah?

00:12:46.800 --> 00:12:48.100 align:middle line:90%
Sorry, they got a little close.

00:12:48.100 --> 00:12:48.300 align:middle line:90%
AUDIENCE: Oh.

00:12:48.300 --> 00:12:50.280 align:middle line:84%
ERIK DEMAINE: So this is
the definition of get_at.

00:12:50.280 --> 00:12:51.840 align:middle line:84%
This is the definition
of sequence build.

00:12:51.840 --> 00:12:52.688 align:middle line:90%
AUDIENCE: Oh, I see.

00:12:52.688 --> 00:12:53.480 align:middle line:90%
ERIK DEMAINE: Yeah.

00:12:53.480 --> 00:12:54.510 align:middle line:90%
Thanks for asking.

00:12:54.510 --> 00:12:57.340 align:middle line:90%


00:12:57.340 --> 00:12:59.730 align:middle line:90%
OK, all good, yeah?

00:12:59.730 --> 00:13:02.653 align:middle line:84%
AUDIENCE: Can you explain
the insert and delete again?

00:13:02.653 --> 00:13:04.320 align:middle line:84%
ERIK DEMAINE: Explain
insert and delete.

00:13:04.320 --> 00:13:09.270 align:middle line:84%
OK, so maybe I should actually
write one of them down,

00:13:09.270 --> 00:13:11.100 align:middle line:84%
or I'll just draw
a picture, maybe.

00:13:11.100 --> 00:13:15.720 align:middle line:84%
So we have this data structure,
which is now a sequence data

00:13:15.720 --> 00:13:20.220 align:middle line:84%
structure, represents
some sequence of items.

00:13:20.220 --> 00:13:23.460 align:middle line:84%
And my goal is to say,
delete the i-th item.

00:13:23.460 --> 00:13:27.930 align:middle line:84%
So there's some items in
here, x0 up to xn minus 1.

00:13:27.930 --> 00:13:31.320 align:middle line:84%
I want to remove xi
from the sequence.

00:13:31.320 --> 00:13:33.640 align:middle line:84%
Or I guess I should
draw it this way.

00:13:33.640 --> 00:13:35.180 align:middle line:90%
It's coming out.

00:13:35.180 --> 00:13:38.020 align:middle line:84%
So what I'm going to do is
first extract all the items

00:13:38.020 --> 00:13:38.870 align:middle line:90%
from the sequence.

00:13:38.870 --> 00:13:40.510 align:middle line:84%
And I didn't write
it, but there's

00:13:40.510 --> 00:13:44.650 align:middle line:84%
an interface over here called
iter, which just gives me

00:13:44.650 --> 00:13:46.760 align:middle line:90%
all the items in order.

00:13:46.760 --> 00:13:50.320 align:middle line:84%
So I'm going to extract
this into an array sequence.

00:13:50.320 --> 00:13:55.240 align:middle line:90%


00:13:55.240 --> 00:13:59.620 align:middle line:84%
Let's say I'll just build
a static array of size n.

00:13:59.620 --> 00:14:01.810 align:middle line:84%
I also have a length
operation that tells me

00:14:01.810 --> 00:14:03.100 align:middle line:90%
how many items are in here.

00:14:03.100 --> 00:14:06.910 align:middle line:84%
And the iter operation will
give me all the items in order.

00:14:06.910 --> 00:14:11.000 align:middle line:84%
And so I'll put into my
array x0 and then x1,

00:14:11.000 --> 00:14:13.700 align:middle line:90%
and so on, as they come out.

00:14:13.700 --> 00:14:17.140 align:middle line:90%
Then I go to position i.

00:14:17.140 --> 00:14:20.890 align:middle line:84%
And I want to delete that item
and shift all the others over.

00:14:20.890 --> 00:14:23.290 align:middle line:90%
This is the boring--

00:14:23.290 --> 00:14:28.600 align:middle line:84%
I think we even said how to
do delete_at in dynamic arrays

00:14:28.600 --> 00:14:31.120 align:middle line:90%
in recitation 2, pretty sure.

00:14:31.120 --> 00:14:32.560 align:middle line:90%
So I'm just mimicking that.

00:14:32.560 --> 00:14:35.830 align:middle line:84%
I'm building this just to
get the new order of things.

00:14:35.830 --> 00:14:39.340 align:middle line:84%
And then I'm applying,
via the build operation,

00:14:39.340 --> 00:14:43.570 align:middle line:84%
I'm building a
totally new sequence.

00:14:43.570 --> 00:14:46.895 align:middle line:84%
And that's how I would
implement delete_at, one way.

00:14:46.895 --> 00:14:47.770 align:middle line:90%
There are other ways.

00:14:47.770 --> 00:14:48.270 align:middle line:90%
Yeah?

00:14:48.270 --> 00:14:50.960 align:middle line:84%
AUDIENCE: Do you have
[INAUDIBLE] space [INAUDIBLE],,

00:14:50.960 --> 00:14:51.460 align:middle line:90%
or--

00:14:51.460 --> 00:14:53.640 align:middle line:84%
ERIK DEMAINE: How much
space is this using?

00:14:53.640 --> 00:14:55.515 align:middle line:84%
Oh, problem with space
if you're inserting--

00:14:55.515 --> 00:14:56.890 align:middle line:84%
if you're inserting,
you probably

00:14:56.890 --> 00:14:58.990 align:middle line:84%
want to allocate a static
array of size n plus 1.

00:14:58.990 --> 00:15:01.010 align:middle line:84%
You know exactly
what's going to happen.

00:15:01.010 --> 00:15:03.130 align:middle line:84%
So just allocate a
little bit bigger.

00:15:03.130 --> 00:15:04.760 align:middle line:90%
Then you can do the shift.

00:15:04.760 --> 00:15:06.250 align:middle line:84%
You could also use
dynamic arrays.

00:15:06.250 --> 00:15:08.240 align:middle line:84%
But then you would
get maybe an--

00:15:08.240 --> 00:15:10.240 align:middle line:84%
it's not an amortized
bound, because you're only

00:15:10.240 --> 00:15:12.130 align:middle line:90%
doing one insertion.

00:15:12.130 --> 00:15:14.180 align:middle line:84%
The point is this
is really easy.

00:15:14.180 --> 00:15:15.710 align:middle line:90%
We can spend linear time.

00:15:15.710 --> 00:15:17.920 align:middle line:90%
So we can rebuild the--

00:15:17.920 --> 00:15:20.930 align:middle line:84%
we can rebuild this array
three times if we wanted.

00:15:20.930 --> 00:15:22.190 align:middle line:90%
Question?

00:15:22.190 --> 00:15:23.910 align:middle line:84%
AUDIENCE: What if
you weren't allowed

00:15:23.910 --> 00:15:27.488 align:middle line:90%
external non-constant space?

00:15:27.488 --> 00:15:28.238 align:middle line:90%
ERIK DEMAINE: Huh.

00:15:28.238 --> 00:15:29.988 align:middle line:84%
You're going to throw
me and open problem.

00:15:29.988 --> 00:15:32.275 align:middle line:84%
What if you only have
constant extra space?

00:15:32.275 --> 00:15:36.750 align:middle line:90%


00:15:36.750 --> 00:15:37.350 align:middle line:90%
Right.

00:15:37.350 --> 00:15:40.050 align:middle line:84%
Then I think we need to
use insert and delete.

00:15:40.050 --> 00:15:44.160 align:middle line:90%
So we could-- good question.

00:15:44.160 --> 00:15:46.590 align:middle line:84%
We could conceptually
do this shifting,

00:15:46.590 --> 00:15:48.960 align:middle line:84%
but do it using
insert and delete.

00:15:48.960 --> 00:15:53.730 align:middle line:84%
So we can-- so let's do
the delete case again.

00:15:53.730 --> 00:15:56.190 align:middle line:90%
So we want to--

00:15:56.190 --> 00:15:57.030 align:middle line:90%
here's xi.

00:15:57.030 --> 00:16:00.330 align:middle line:84%
We want to replace it
with xi plus 1 and so on.

00:16:00.330 --> 00:16:04.380 align:middle line:90%


00:16:04.380 --> 00:16:10.170 align:middle line:84%
And so we can start out by
deleting the item with key i.

00:16:10.170 --> 00:16:12.060 align:middle line:90%
That will get rid of this guy.

00:16:12.060 --> 00:16:16.920 align:middle line:84%
Then we can delete the
item with key i plus 1.

00:16:16.920 --> 00:16:18.630 align:middle line:90%
And that gives us the item.

00:16:18.630 --> 00:16:23.310 align:middle line:84%
And then we can reassign its
key to i instead of i plus 1

00:16:23.310 --> 00:16:25.200 align:middle line:90%
and then reinsert it.

00:16:25.200 --> 00:16:27.060 align:middle line:90%
So we can take this item out.

00:16:27.060 --> 00:16:30.516 align:middle line:90%
It has a key, which is--

00:16:30.516 --> 00:16:31.770 align:middle line:90%
I'll draw this properly.

00:16:31.770 --> 00:16:37.200 align:middle line:84%
So we have key i
plus 1 and value xi

00:16:37.200 --> 00:16:40.350 align:middle line:84%
plus 1 stored in
this data structure.

00:16:40.350 --> 00:16:43.260 align:middle line:90%
Then we update the key to i.

00:16:43.260 --> 00:16:44.700 align:middle line:90%
And then we reinsert it.

00:16:44.700 --> 00:16:46.955 align:middle line:84%
And it takes the
place of this guy.

00:16:46.955 --> 00:16:47.830 align:middle line:90%
So you could do that.

00:16:47.830 --> 00:16:50.220 align:middle line:84%
You could go down this
list and-- or not the list,

00:16:50.220 --> 00:16:52.980 align:middle line:84%
but you could iterate
for i equals-- sorry,

00:16:52.980 --> 00:16:56.370 align:middle line:84%
for j equals i to n minus 1,
and for each of those items,

00:16:56.370 --> 00:16:59.688 align:middle line:84%
delete it, change its key,
reinsert it with the new key.

00:16:59.688 --> 00:17:01.980 align:middle line:84%
And then you don't have to
build this intermediate data

00:17:01.980 --> 00:17:03.100 align:middle line:90%
structure.

00:17:03.100 --> 00:17:05.335 align:middle line:84%
So if you're told to
minimize space, great.

00:17:05.335 --> 00:17:06.960 align:middle line:84%
And maybe you think
of that as simpler.

00:17:06.960 --> 00:17:09.000 align:middle line:84%
I like to think of this
as simpler, because I--

00:17:09.000 --> 00:17:10.208 align:middle line:90%
point is, I have linear time.

00:17:10.208 --> 00:17:14.069 align:middle line:84%
I can do crazy, silly, very
non-data-structures-y things,

00:17:14.069 --> 00:17:16.670 align:middle line:90%
where I just start from scratch.

00:17:16.670 --> 00:17:18.619 align:middle line:90%
OK, great.

00:17:18.619 --> 00:17:20.510 align:middle line:84%
But there's one more
set of operations,

00:17:20.510 --> 00:17:23.609 align:middle line:90%
insert, delete, first and last.

00:17:23.609 --> 00:17:26.339 align:middle line:90%
Are these easy?

00:17:26.339 --> 00:17:26.839 align:middle line:90%
Good?

00:17:26.839 --> 00:17:33.540 align:middle line:90%


00:17:33.540 --> 00:17:35.340 align:middle line:90%
Shall we try?

00:17:35.340 --> 00:17:40.440 align:middle line:90%
We can insert last.

00:17:40.440 --> 00:17:44.520 align:middle line:84%
So this is given an item,
x, we want to add it

00:17:44.520 --> 00:17:45.790 align:middle line:90%
to the end of the structure.

00:17:45.790 --> 00:17:48.928 align:middle line:84%
So that means its index is going
to be equal to-- because we

00:17:48.928 --> 00:17:50.970 align:middle line:84%
start at 0, it's going to
be equal to the length,

00:17:50.970 --> 00:17:52.780 align:middle line:90%
current length of the structure.

00:17:52.780 --> 00:17:57.350 align:middle line:84%
So let's just insert
a new object, which

00:17:57.350 --> 00:18:00.720 align:middle line:90%
has key equal to the length.

00:18:00.720 --> 00:18:04.240 align:middle line:90%
And it has value equal to x.

00:18:04.240 --> 00:18:05.310 align:middle line:90%
We're done.

00:18:05.310 --> 00:18:06.690 align:middle line:90%
Delete last, similar.

00:18:06.690 --> 00:18:10.740 align:middle line:84%
Just delete the item
with key length minus 1.

00:18:10.740 --> 00:18:11.760 align:middle line:90%
OK, what about first?

00:18:11.760 --> 00:18:17.170 align:middle line:90%


00:18:17.170 --> 00:18:19.905 align:middle line:84%
This is supposed to add x to
the beginning of my sequence.

00:18:19.905 --> 00:18:22.810 align:middle line:90%


00:18:22.810 --> 00:18:25.120 align:middle line:84%
Well, now I realize
I have a problem,

00:18:25.120 --> 00:18:29.830 align:middle line:84%
because I want this
new item to have key 0,

00:18:29.830 --> 00:18:33.700 align:middle line:84%
because after I do an
insert first, get_at of 0

00:18:33.700 --> 00:18:35.530 align:middle line:90%
should return this item.

00:18:35.530 --> 00:18:39.370 align:middle line:84%
But I already have an item with
key 0, and an item with key 1,

00:18:39.370 --> 00:18:41.990 align:middle line:84%
and an item with key 2,
and so on down the way.

00:18:41.990 --> 00:18:44.170 align:middle line:84%
And so if I wanted
to give x a key of 0,

00:18:44.170 --> 00:18:46.750 align:middle line:84%
I have to shift the keys
of all of those items,

00:18:46.750 --> 00:18:48.320 align:middle line:90%
just like we were doing here.

00:18:48.320 --> 00:18:50.890 align:middle line:84%
And that's going to
take linear time.

00:18:50.890 --> 00:18:54.320 align:middle line:84%
But we were supposed to do this
in constant expected amortized

00:18:54.320 --> 00:18:55.640 align:middle line:90%
time.

00:18:55.640 --> 00:18:57.800 align:middle line:90%
So that's no good.

00:18:57.800 --> 00:19:00.890 align:middle line:90%
So this idea is not enough.

00:19:00.890 --> 00:19:01.850 align:middle line:90%
It's not a bad idea.

00:19:01.850 --> 00:19:03.190 align:middle line:90%
It's still a good idea.

00:19:03.190 --> 00:19:05.770 align:middle line:84%
But it's no longer what
we actually want to do.

00:19:05.770 --> 00:19:09.430 align:middle line:84%
It's only morally
what we want to do.

00:19:09.430 --> 00:19:13.750 align:middle line:84%
So do you have any thoughts
on how we might get around

00:19:13.750 --> 00:19:15.760 align:middle line:90%
this problem?

00:19:15.760 --> 00:19:17.630 align:middle line:84%
Seems like inserting
at position 0,

00:19:17.630 --> 00:19:20.095 align:middle line:84%
I need to shift everything
down, linear time.

00:19:20.095 --> 00:19:20.965 align:middle line:90%
That really sucks.

00:19:20.965 --> 00:19:28.680 align:middle line:90%


00:19:28.680 --> 00:19:31.310 align:middle line:90%
Yeah?

00:19:31.310 --> 00:19:36.210 align:middle line:84%
AUDIENCE: You could create some
sort of link to something else.

00:19:36.210 --> 00:19:38.640 align:middle line:84%
ERIK DEMAINE: Link this data
structure with another one.

00:19:38.640 --> 00:19:40.140 align:middle line:84%
So we could build
more than one set.

00:19:40.140 --> 00:19:41.182 align:middle line:90%
That's certainly allowed.

00:19:41.182 --> 00:19:45.260 align:middle line:90%


00:19:45.260 --> 00:19:46.940 align:middle line:84%
I don't know how
to do-- oh, I see.

00:19:46.940 --> 00:19:49.070 align:middle line:84%
You're saying maybe build
a whole other structure

00:19:49.070 --> 00:19:51.620 align:middle line:84%
for the items that
come before 0?

00:19:51.620 --> 00:19:52.820 align:middle line:90%
AUDIENCE: Yeah.

00:19:52.820 --> 00:19:54.028 align:middle line:90%
ERIK DEMAINE: Yeah, actually.

00:19:54.028 --> 00:19:57.260 align:middle line:90%
That would work, I think, maybe.

00:19:57.260 --> 00:19:58.490 align:middle line:90%
It's like in the P set.

00:19:58.490 --> 00:20:01.280 align:middle line:84%
Then you have to deal
with when-- if you delete

00:20:01.280 --> 00:20:02.630 align:middle line:90%
one of them, it becomes empty.

00:20:02.630 --> 00:20:04.340 align:middle line:90%
Then things get messy.

00:20:04.340 --> 00:20:07.280 align:middle line:84%
Delete first is also going
to be a problem, because I

00:20:07.280 --> 00:20:11.970 align:middle line:84%
delete beginning of
this data structure,

00:20:11.970 --> 00:20:13.820 align:middle line:90%
then I lose my 0 item.

00:20:13.820 --> 00:20:16.850 align:middle line:84%
And I want the new 0
item to be the 1 item.

00:20:16.850 --> 00:20:18.500 align:middle line:84%
And again, all
the indices shift.

00:20:18.500 --> 00:20:21.230 align:middle line:84%
So delete and inserting
at the first is hard.

00:20:21.230 --> 00:20:23.720 align:middle line:84%
So we could do that trick
like in the P set, but--

00:20:23.720 --> 00:20:27.540 align:middle line:84%
or like in the last
problem session and so on.

00:20:27.540 --> 00:20:31.629 align:middle line:90%
But there's a much simpler idea.

00:20:31.629 --> 00:20:33.296 align:middle line:84%
AUDIENCE: Can you
have an extra variable

00:20:33.296 --> 00:20:35.453 align:middle line:84%
to keep track of where
is the beginning?

00:20:35.453 --> 00:20:36.245 align:middle line:90%
ERIK DEMAINE: Nice.

00:20:36.245 --> 00:20:38.930 align:middle line:84%
I can have an extra
variable to keep track

00:20:38.930 --> 00:20:40.190 align:middle line:90%
of where the beginning is.

00:20:40.190 --> 00:20:52.084 align:middle line:90%


00:20:52.084 --> 00:20:54.390 align:middle line:90%
Call this first.

00:20:54.390 --> 00:21:08.090 align:middle line:84%
This is going to be the key
of the first item, index 0.

00:21:08.090 --> 00:21:10.130 align:middle line:84%
Another way to say
this is, let's just

00:21:10.130 --> 00:21:13.100 align:middle line:90%
use negative integers, right?

00:21:13.100 --> 00:21:15.920 align:middle line:84%
Sets work for any
keys, any integer keys.

00:21:15.920 --> 00:21:17.360 align:middle line:84%
OK, actually, we
technically said,

00:21:17.360 --> 00:21:19.670 align:middle line:84%
make sure you use
keys 0 to u minus 1.

00:21:19.670 --> 00:21:24.290 align:middle line:84%
But then, if you have negative
numbers, you can easily fold--

00:21:24.290 --> 00:21:26.435 align:middle line:84%
AUDIENCE: Wait, doesn't
it [INAUDIBLE] to like

00:21:26.435 --> 00:21:27.205 align:middle line:90%
[INAUDIBLE]?

00:21:27.205 --> 00:21:27.913 align:middle line:90%
ERIK DEMAINE: Ah.

00:21:27.913 --> 00:21:29.850 align:middle line:84%
Python negative numbers
mean something else.

00:21:29.850 --> 00:21:31.475 align:middle line:84%
But we're not using
a Python interface.

00:21:31.475 --> 00:21:34.760 align:middle line:84%
We're using our custom
magical set interface,

00:21:34.760 --> 00:21:38.090 align:middle line:84%
which we show how to implement
in recitation notes, which

00:21:38.090 --> 00:21:40.280 align:middle line:90%
can take an arbitrary key.

00:21:40.280 --> 00:21:46.040 align:middle line:84%
It hashes that key and finds
a place to put that item.

00:21:46.040 --> 00:21:48.338 align:middle line:84%
So we're not actually
storing things in order here.

00:21:48.338 --> 00:21:49.880 align:middle line:84%
We're storing things
in a hash table.

00:21:49.880 --> 00:21:52.160 align:middle line:84%
But we're not supposed to
get into the implementation

00:21:52.160 --> 00:21:52.940 align:middle line:90%
details.

00:21:52.940 --> 00:21:56.720 align:middle line:84%
I think the way we presented
hashing with our universal hash

00:21:56.720 --> 00:21:59.220 align:middle line:84%
functions, we only
allowed positive numbers.

00:21:59.220 --> 00:22:01.980 align:middle line:84%
So maybe, technically,
I should point out,

00:22:01.980 --> 00:22:07.430 align:middle line:84%
if you have positive
and negative numbers,

00:22:07.430 --> 00:22:15.260 align:middle line:84%
you can fold this in half by
mapping 0 to 0, 1 to 2, 2 to 4,

00:22:15.260 --> 00:22:17.300 align:middle line:90%
spreading it out.

00:22:17.300 --> 00:22:19.760 align:middle line:84%
And then you can take
minus 1 and map it

00:22:19.760 --> 00:22:23.750 align:middle line:84%
to plus 1, and minus 2
and map it to plus 3.

00:22:23.750 --> 00:22:26.540 align:middle line:84%
So this is like multiplying
each of these guys by 2,

00:22:26.540 --> 00:22:30.200 align:middle line:84%
and multiplying each of these
guys by minus 2 and adding 1.

00:22:30.200 --> 00:22:35.960 align:middle line:84%
And then you get non-negative
integers out of all integers.

00:22:35.960 --> 00:22:40.100 align:middle line:84%
This is a typical
math trick for showing

00:22:40.100 --> 00:22:42.320 align:middle line:84%
that the number of integers
is equal to the number

00:22:42.320 --> 00:22:45.140 align:middle line:84%
of non-negative integers,
which may seem weird to you.

00:22:45.140 --> 00:22:48.410 align:middle line:84%
But they're both
countably infinite.

00:22:48.410 --> 00:22:50.690 align:middle line:84%
So you could-- if your
structure only supports

00:22:50.690 --> 00:22:53.930 align:middle line:84%
non-negative keys, you could
map negative keys in this way

00:22:53.930 --> 00:22:57.200 align:middle line:84%
and throw them into
the hash table, OK?

00:22:57.200 --> 00:23:00.170 align:middle line:84%
So now, I allow
negative things for--

00:23:00.170 --> 00:23:03.490 align:middle line:90%


00:23:03.490 --> 00:23:04.250 align:middle line:90%
like that.

00:23:04.250 --> 00:23:05.230 align:middle line:90%
And so, great.

00:23:05.230 --> 00:23:08.080 align:middle line:84%
If I want to insert at the
beginning, what I can do

00:23:08.080 --> 00:23:14.080 align:middle line:84%
is just decrement my
first variable, which

00:23:14.080 --> 00:23:15.450 align:middle line:90%
is keeping track of the index.

00:23:15.450 --> 00:23:17.920 align:middle line:84%
So initially, first
is going to be 0.

00:23:17.920 --> 00:23:20.590 align:middle line:84%
So I'm going to
add into my build.

00:23:20.590 --> 00:23:23.500 align:middle line:84%
First, I'm going
to say first equals

00:23:23.500 --> 00:23:28.270 align:middle line:84%
0, because I start with
key 0 when I initially

00:23:28.270 --> 00:23:29.680 align:middle line:90%
build a structure.

00:23:29.680 --> 00:23:31.930 align:middle line:84%
And if I want to-- if I
need more room before 0,

00:23:31.930 --> 00:23:34.240 align:middle line:90%
I just set first to minus 1.

00:23:34.240 --> 00:23:36.400 align:middle line:84%
And if I already have
a minus 1 element,

00:23:36.400 --> 00:23:38.040 align:middle line:90%
I'll decrement it to minus 2.

00:23:38.040 --> 00:23:40.600 align:middle line:90%
Decrement means decrease by 1--

00:23:40.600 --> 00:23:42.640 align:middle line:84%
shows my assembly
language programming.

00:23:42.640 --> 00:23:45.550 align:middle line:84%
This is usually a built-in
operation on most computers.

00:23:45.550 --> 00:23:55.690 align:middle line:84%
And then I can insert an item
with key first and value x.

00:23:55.690 --> 00:23:58.410 align:middle line:90%


00:23:58.410 --> 00:23:58.910 align:middle line:90%
Great.

00:23:58.910 --> 00:24:01.020 align:middle line:84%
And if I want to
delete the first item,

00:24:01.020 --> 00:24:05.850 align:middle line:84%
I would delete the item with key
first and then increment first.

00:24:05.850 --> 00:24:08.720 align:middle line:84%
And now all of my operations
have to change a little bit--

00:24:08.720 --> 00:24:11.030 align:middle line:90%
let me use another color--

00:24:11.030 --> 00:24:13.190 align:middle line:84%
because I was
implicitly assuming here

00:24:13.190 --> 00:24:15.320 align:middle line:84%
that all my indices
started at i.

00:24:15.320 --> 00:24:16.850 align:middle line:90%
But now they start at first.

00:24:16.850 --> 00:24:22.730 align:middle line:90%
The index 0 maps to key first.

00:24:22.730 --> 00:24:24.680 align:middle line:84%
And so the right
thing to do here

00:24:24.680 --> 00:24:31.370 align:middle line:90%
is plus first and plus first.

00:24:31.370 --> 00:24:35.930 align:middle line:84%
Basically, add a whole bunch
of plus firsts throughout.

00:24:35.930 --> 00:24:37.080 align:middle line:90%
This one is probably fine.

00:24:37.080 --> 00:24:40.550 align:middle line:84%
If I'm globally rebuilding,
I can reassign all my labels.

00:24:40.550 --> 00:24:44.840 align:middle line:84%
But this one should
be first plus length.

00:24:44.840 --> 00:24:47.630 align:middle line:90%


00:24:47.630 --> 00:24:52.760 align:middle line:84%
OK, so just by keeping track
of where my keys are starting,

00:24:52.760 --> 00:24:56.510 align:middle line:84%
I can do this shifting and
not have to worry about stuff.

00:24:56.510 --> 00:24:59.630 align:middle line:84%
And this is a lot easier
than having to worry about

00:24:59.630 --> 00:25:03.290 align:middle line:84%
maintaining two structures, and
keeping them both non-empty,

00:25:03.290 --> 00:25:06.070 align:middle line:84%
and stuff like
that, because of--

00:25:06.070 --> 00:25:08.780 align:middle line:84%
if I assume my
mindset has this power

00:25:08.780 --> 00:25:11.420 align:middle line:84%
of dealing with negative
integers, and strings,

00:25:11.420 --> 00:25:14.450 align:middle line:90%
and whatever else.

00:25:14.450 --> 00:25:15.400 align:middle line:90%
Cool?

00:25:15.400 --> 00:25:15.900 align:middle line:90%
Yeah?

00:25:15.900 --> 00:25:17.330 align:middle line:84%
AUDIENCE: Is there a
reason why you didn't do

00:25:17.330 --> 00:25:18.490 align:middle line:90%
like the sorting--

00:25:18.490 --> 00:25:21.870 align:middle line:90%
like, have [INAUDIBLE]?

00:25:21.870 --> 00:25:24.130 align:middle line:84%
ERIK DEMAINE: Oh, why
didn't I use a linked list?

00:25:24.130 --> 00:25:27.790 align:middle line:90%
Because this.

00:25:27.790 --> 00:25:32.440 align:middle line:84%
Linked lists are very bad at
get and set at a given index.

00:25:32.440 --> 00:25:33.400 align:middle line:90%
AUDIENCE: Is that the--

00:25:33.400 --> 00:25:35.025 align:middle line:84%
the bottom idea, is
that a linked list?

00:25:35.025 --> 00:25:36.692 align:middle line:84%
ERIK DEMAINE: This
is not a linked list.

00:25:36.692 --> 00:25:38.200 align:middle line:84%
This is just storing
a single number

00:25:38.200 --> 00:25:41.050 align:middle line:84%
as integer in your data
structure that says,

00:25:41.050 --> 00:25:44.660 align:middle line:84%
what is the smallest key
in my data structure?

00:25:44.660 --> 00:25:45.970 align:middle line:90%
That's all it this.

00:25:45.970 --> 00:25:47.078 align:middle line:90%
It's a counter.

00:25:47.078 --> 00:25:48.302 align:middle line:90%
AUDIENCE: Ah.

00:25:48.302 --> 00:25:50.027 align:middle line:84%
ERIK DEMAINE: OK,
so data structure

00:25:50.027 --> 00:25:51.110 align:middle line:90%
keeps track of its length.

00:25:51.110 --> 00:25:52.910 align:middle line:84%
And it keeps track
of the minimum key.

00:25:52.910 --> 00:25:55.100 align:middle line:84%
And so it will always
consist-- the invariant is,

00:25:55.100 --> 00:25:57.530 align:middle line:84%
you will always
have keys from first

00:25:57.530 --> 00:26:00.290 align:middle line:90%
up to first plus length minus 1.

00:26:00.290 --> 00:26:04.800 align:middle line:84%
And that's what we're
exploiting here.

00:26:04.800 --> 00:26:06.330 align:middle line:84%
We have no idea
where first will be.

00:26:06.330 --> 00:26:08.430 align:middle line:84%
It depends how many
operations you've done,

00:26:08.430 --> 00:26:10.510 align:middle line:84%
how many inserts at the
beginning, and so on.

00:26:10.510 --> 00:26:23.520 align:middle line:84%
But the keys-- keys will
always be first to first plus

00:26:23.520 --> 00:26:26.433 align:middle line:90%
length minus 1.

00:26:26.433 --> 00:26:27.850 align:middle line:84%
This is what we
call an invariant.

00:26:27.850 --> 00:26:31.200 align:middle line:84%
Useful to write
these things down so

00:26:31.200 --> 00:26:32.970 align:middle line:84%
you can understand
what the heck--

00:26:32.970 --> 00:26:35.077 align:middle line:84%
why is your data
structure correct?

00:26:35.077 --> 00:26:36.660 align:middle line:84%
Because of invariants
like this, which

00:26:36.660 --> 00:26:39.072 align:middle line:84%
you can prove by
induction, by showing,

00:26:39.072 --> 00:26:40.530 align:middle line:84%
each time you do
an operation, this

00:26:40.530 --> 00:26:44.130 align:middle line:84%
is maintained, even when
I'm changing first in order

00:26:44.130 --> 00:26:47.820 align:middle line:90%
to maintain this invariant.

00:26:47.820 --> 00:26:48.352 align:middle line:90%
Cool.

00:26:48.352 --> 00:26:50.310 align:middle line:84%
Sometimes you come up
with the invariant first.

00:26:50.310 --> 00:26:57.010 align:middle line:84%
In this case, I came up with
it post facto, after the fact.

00:26:57.010 --> 00:26:58.510 align:middle line:90%
Cool.

00:26:58.510 --> 00:27:18.760 align:middle line:84%
Let's move on to problem 3,
which is called critter sort.

00:27:18.760 --> 00:27:21.600 align:middle line:84%
And the other key thing I
want you to learn about--

00:27:21.600 --> 00:27:22.100 align:middle line:90%
question?

00:27:22.100 --> 00:27:22.600 align:middle line:90%
Sorry.

00:27:22.600 --> 00:27:23.480 align:middle line:90%
AUDIENCE: Yeah.

00:27:23.480 --> 00:27:25.547 align:middle line:84%
So when you do
first, first plus 1,

00:27:25.547 --> 00:27:28.247 align:middle line:84%
is that a rebuilding
of the [INAUDIBLE]??

00:27:28.247 --> 00:27:29.830 align:middle line:84%
ERIK DEMAINE: This
is just a sentence.

00:27:29.830 --> 00:27:32.720 align:middle line:84%
It is not an algorithm
or data structure.

00:27:32.720 --> 00:27:34.115 align:middle line:90%
This is a mathematical property.

00:27:34.115 --> 00:27:34.990 align:middle line:90%
AUDIENCE: [INAUDIBLE]

00:27:34.990 --> 00:27:36.770 align:middle line:84%
ERIK DEMAINE: This
is not an assignment.

00:27:36.770 --> 00:27:38.800 align:middle line:84%
This is a mathematically
is equal to.

00:27:38.800 --> 00:27:41.920 align:middle line:84%
AUDIENCE: But you are
re-indexing it though,

00:27:41.920 --> 00:27:43.630 align:middle line:84%
because you're
doing first plus 1.

00:27:43.630 --> 00:27:46.480 align:middle line:84%
ERIK DEMAINE: So are you asking
about one of these operations,

00:27:46.480 --> 00:27:48.142 align:middle line:90%
like this one?

00:27:48.142 --> 00:27:48.850 align:middle line:90%
AUDIENCE: Oh, OK.

00:27:48.850 --> 00:27:49.090 align:middle line:90%
Never mind.

00:27:49.090 --> 00:27:49.530 align:middle line:90%
I get it.

00:27:49.530 --> 00:27:50.030 align:middle line:90%
OK.

00:27:50.030 --> 00:27:51.830 align:middle line:90%
ERIK DEMAINE: Yeah.

00:27:51.830 --> 00:27:52.600 align:middle line:90%
OK.

00:27:52.600 --> 00:27:54.160 align:middle line:84%
So the other
important takeaway I

00:27:54.160 --> 00:27:56.350 align:middle line:84%
want you to get about
reading our problem sets

00:27:56.350 --> 00:27:58.630 align:middle line:84%
is that they have
hidden humor inside.

00:27:58.630 --> 00:28:00.470 align:middle line:90%
I don't know if you've noticed.

00:28:00.470 --> 00:28:02.950 align:middle line:84%
But here's an example of a
problem called critter sort.

00:28:02.950 --> 00:28:05.770 align:middle line:84%
Ashley Gettem collects
and trains pocket critters

00:28:05.770 --> 00:28:07.750 align:middle line:84%
to fight other pocket
critters in battle.

00:28:07.750 --> 00:28:09.235 align:middle line:90%
What is this a reference to?

00:28:09.235 --> 00:28:10.313 align:middle line:90%
AUDIENCE: Digimon.

00:28:10.313 --> 00:28:11.230 align:middle line:90%
ERIK DEMAINE: Digimon.

00:28:11.230 --> 00:28:13.150 align:middle line:90%
Wow, you guys are so young.

00:28:13.150 --> 00:28:16.990 align:middle line:90%
Pokemon, the ancient form.

00:28:16.990 --> 00:28:19.690 align:middle line:84%
Pokemon is short
for pocket monsters.

00:28:19.690 --> 00:28:20.950 align:middle line:90%
And in fact, in the original--

00:28:20.950 --> 00:28:21.490 align:middle line:90%
AUDIENCE: [INAUDIBLE]

00:28:21.490 --> 00:28:22.448 align:middle line:90%
ERIK DEMAINE: --anime--

00:28:22.448 --> 00:28:24.160 align:middle line:84%
AUDIENCE: Actually,
there's [INAUDIBLE]..

00:28:24.160 --> 00:28:25.285 align:middle line:90%
ERIK DEMAINE: I don't know.

00:28:25.285 --> 00:28:27.880 align:middle line:90%
This is all after my time.

00:28:27.880 --> 00:28:28.845 align:middle line:90%
We can debate after.

00:28:28.845 --> 00:28:30.220 align:middle line:84%
So pocket critters
is a reference

00:28:30.220 --> 00:28:33.130 align:middle line:84%
to pocket monsters,
which is Pokemon.

00:28:33.130 --> 00:28:35.240 align:middle line:90%
Who's Ashley Gettem?

00:28:35.240 --> 00:28:36.400 align:middle line:90%
AUDIENCE: Ash.

00:28:36.400 --> 00:28:38.470 align:middle line:84%
ERIK DEMAINE: Ash
Ketchum is his full name

00:28:38.470 --> 00:28:40.952 align:middle line:90%
in the English version.

00:28:40.952 --> 00:28:42.910 align:middle line:84%
Totally different name
in the Japanese version.

00:28:42.910 --> 00:28:46.090 align:middle line:84%
But they're both puns on
collect them all, right?

00:28:46.090 --> 00:28:48.040 align:middle line:84%
All right, so that's
the important stuff.

00:28:48.040 --> 00:28:50.240 align:middle line:90%
We'll see more jokes later.

00:28:50.240 --> 00:28:51.640 align:middle line:90%
So there's this setup.

00:28:51.640 --> 00:28:54.280 align:middle line:84%
But basically, we
have n critters.

00:28:54.280 --> 00:28:57.290 align:middle line:84%
And we want to sort them
by four different things.

00:28:57.290 --> 00:28:59.590 align:middle line:84%
And so I'm just going
to abstract this problem

00:28:59.590 --> 00:29:04.438 align:middle line:84%
to sort n objects by the
following types of keys.

00:29:04.438 --> 00:29:06.730 align:middle line:84%
And for each one, we want to
know what the best sorting

00:29:06.730 --> 00:29:08.200 align:middle line:90%
algorithm is.

00:29:08.200 --> 00:29:10.990 align:middle line:84%
And there's this footnote
that's very important that says,

00:29:10.990 --> 00:29:13.420 align:middle line:84%
faster correct algorithms
will receive more points

00:29:13.420 --> 00:29:15.938 align:middle line:90%
than slower correct algorithms.

00:29:15.938 --> 00:29:17.980 align:middle line:84%
Also, correct algorithms
will receive more points

00:29:17.980 --> 00:29:19.150 align:middle line:90%
than incorrect algorithms.

00:29:19.150 --> 00:29:20.230 align:middle line:90%
But that's implicit.

00:29:20.230 --> 00:29:22.330 align:middle line:90%
Incorrect generally gets zero.

00:29:22.330 --> 00:29:27.340 align:middle line:84%
OK, so part a, it
says, species ID.

00:29:27.340 --> 00:29:36.400 align:middle line:84%
But basically, we have integers
and the range minus n to n.

00:29:36.400 --> 00:29:40.900 align:middle line:84%
So if I want to sort n integers
in the range minus n to n,

00:29:40.900 --> 00:29:42.340 align:middle line:90%
what should I do?

00:29:42.340 --> 00:29:45.550 align:middle line:84%
This is a reference to
yesterday's lecture.

00:29:45.550 --> 00:29:50.170 align:middle line:90%


00:29:50.170 --> 00:29:51.350 align:middle line:90%
Yeah?

00:29:51.350 --> 00:29:52.800 align:middle line:90%
Radix sort, yeah.

00:29:52.800 --> 00:29:54.005 align:middle line:90%
Always a good answer.

00:29:54.005 --> 00:29:56.990 align:middle line:84%
Or almost always a good
answer when you have integers.

00:29:56.990 --> 00:29:59.640 align:middle line:84%
It's a good answer whenever
you have small integers.

00:29:59.640 --> 00:30:01.590 align:middle line:84%
Now, radix sort, the
way we phrased it--

00:30:01.590 --> 00:30:04.010 align:middle line:90%
let me maybe put it down here.

00:30:04.010 --> 00:30:20.270 align:middle line:84%
Radix sort sorts n integers in
the range 0 to u minus 1 in n

00:30:20.270 --> 00:30:25.910 align:middle line:90%
plus n log base n of u time.

00:30:25.910 --> 00:30:28.460 align:middle line:90%


00:30:28.460 --> 00:30:31.800 align:middle line:84%
And in particular,
this is linear time

00:30:31.800 --> 00:30:38.420 align:middle line:84%
if u is n to some
constant power.

00:30:38.420 --> 00:30:43.430 align:middle line:84%
OK, so can I just apply this
as is to these integers?

00:30:43.430 --> 00:30:45.987 align:middle line:90%
No, because they're negative.

00:30:45.987 --> 00:30:46.820 align:middle line:90%
So what should I do?

00:30:46.820 --> 00:30:48.278 align:middle line:84%
Maybe I should do
my folding trick.

00:30:48.278 --> 00:30:51.440 align:middle line:84%
We just saw how to take negative
numbers and fold them in,

00:30:51.440 --> 00:30:53.160 align:middle line:84%
interspersed with
positive numbers.

00:30:53.160 --> 00:30:57.900 align:middle line:90%
If I sort that, will that work?

00:30:57.900 --> 00:31:00.960 align:middle line:84%
No, because that does
not preserve order.

00:31:00.960 --> 00:31:03.335 align:middle line:90%
It would intersperse.

00:31:03.335 --> 00:31:05.460 align:middle line:84%
We want all the negative
numbers to come before all

00:31:05.460 --> 00:31:06.240 align:middle line:90%
the positive numbers.

00:31:06.240 --> 00:31:06.630 align:middle line:90%
Yeah?

00:31:06.630 --> 00:31:08.672 align:middle line:84%
AUDIENCE: Can you just
add n to all the integers?

00:31:08.672 --> 00:31:10.485 align:middle line:90%
ERIK DEMAINE: Just add n, yep.

00:31:10.485 --> 00:31:11.190 align:middle line:90%
Boom.

00:31:11.190 --> 00:31:11.970 align:middle line:90%
Plus n.

00:31:11.970 --> 00:31:14.730 align:middle line:84%
Now we have integers
in the range--

00:31:14.730 --> 00:31:16.020 align:middle line:90%
let's be careful--

00:31:16.020 --> 00:31:17.640 align:middle line:90%
0 to 2n.

00:31:17.640 --> 00:31:21.130 align:middle line:90%


00:31:21.130 --> 00:31:21.630 align:middle line:90%
Cool.

00:31:21.630 --> 00:31:22.650 align:middle line:90%
Now we can apply this.

00:31:22.650 --> 00:31:25.470 align:middle line:84%
Now u equals,
technically, 2n plus 1,

00:31:25.470 --> 00:31:27.833 align:middle line:84%
because we're only supposed
to go to u minus 1.

00:31:27.833 --> 00:31:28.500 align:middle line:90%
But that's fine.

00:31:28.500 --> 00:31:29.490 align:middle line:90%
That's linear.

00:31:29.490 --> 00:31:32.220 align:middle line:84%
And so we can sort
in linear time, easy.

00:31:32.220 --> 00:31:34.850 align:middle line:90%
This is a super easy problem.

00:31:34.850 --> 00:31:37.500 align:middle line:84%
But in each one, we might need
to do some transformation.

00:31:37.500 --> 00:31:41.410 align:middle line:84%
Part b is a little
more interesting.

00:31:41.410 --> 00:31:58.230 align:middle line:84%
So we have strings over 26
letters of length at most

00:31:58.230 --> 00:32:00.930 align:middle line:90%
10 ceiling log n.

00:32:00.930 --> 00:32:03.640 align:middle line:90%


00:32:03.640 --> 00:32:05.160 align:middle line:90%
OK, this is a little trickier.

00:32:05.160 --> 00:32:06.300 align:middle line:90%
What could I do?

00:32:06.300 --> 00:32:10.350 align:middle line:84%
Again, I'd like to see
whether radix sort applies.

00:32:10.350 --> 00:32:12.120 align:middle line:90%
I should say radix sort sorts.

00:32:12.120 --> 00:32:15.420 align:middle line:90%


00:32:15.420 --> 00:32:17.130 align:middle line:84%
I'd like to see if
radix sort applies.

00:32:17.130 --> 00:32:20.550 align:middle line:84%
To do that, I have to map these
strings into integers somehow.

00:32:20.550 --> 00:32:21.510 align:middle line:90%
Any way to do that?

00:32:21.510 --> 00:32:24.405 align:middle line:90%


00:32:24.405 --> 00:32:26.155 align:middle line:84%
This is easy if you
understand radix sort.

00:32:26.155 --> 00:32:26.655 align:middle line:90%
Yeah?

00:32:26.655 --> 00:32:29.180 align:middle line:84%
AUDIENCE: Can you just
index the letters?

00:32:29.180 --> 00:32:30.618 align:middle line:84%
ERIK DEMAINE:
Index, the letters.

00:32:30.618 --> 00:32:31.118 align:middle line:90%
Yeah.

00:32:31.118 --> 00:32:34.610 align:middle line:90%


00:32:34.610 --> 00:32:35.910 align:middle line:90%
Yeah, we can map--

00:32:35.910 --> 00:32:36.410 align:middle line:90%
right.

00:32:36.410 --> 00:32:39.150 align:middle line:90%
So we can map A to 0, B to 1.

00:32:39.150 --> 00:32:39.650 align:middle line:90%
Then what?

00:32:39.650 --> 00:32:42.288 align:middle line:90%


00:32:42.288 --> 00:32:43.080 align:middle line:90%
AUDIENCE: Oh, wait.

00:32:43.080 --> 00:32:45.170 align:middle line:90%
Length--

00:32:45.170 --> 00:32:48.050 align:middle line:84%
ERIK DEMAINE: So
that's for each letter.

00:32:48.050 --> 00:32:52.520 align:middle line:90%
But we have a lot of letters.

00:32:52.520 --> 00:32:53.660 align:middle line:90%
There are only 26 letters.

00:32:53.660 --> 00:32:58.070 align:middle line:84%
But then we have 10 log
n letters in a string.

00:32:58.070 --> 00:33:00.920 align:middle line:84%
That is, together, a single
key that we need to sort.

00:33:00.920 --> 00:33:05.130 align:middle line:90%


00:33:05.130 --> 00:33:05.630 align:middle line:90%
Yeah?

00:33:05.630 --> 00:33:09.995 align:middle line:84%
AUDIENCE: Can't we just sort by
the first letter first, then--

00:33:09.995 --> 00:33:12.620 align:middle line:84%
ERIK DEMAINE: Sort by the first
letter, then the second letter.

00:33:12.620 --> 00:33:14.517 align:middle line:84%
That is exactly the
opposite of radix sort.

00:33:14.517 --> 00:33:16.100 align:middle line:84%
Remember, radix sort,
we want to start

00:33:16.100 --> 00:33:18.980 align:middle line:84%
by the last letter, and then
the next to last letter,

00:33:18.980 --> 00:33:20.450 align:middle line:90%
and finally, the first letter.

00:33:20.450 --> 00:33:21.530 align:middle line:84%
AUDIENCE: But you want
to sort by the first one

00:33:21.530 --> 00:33:23.233 align:middle line:90%
in order to alphabetize things.

00:33:23.233 --> 00:33:24.650 align:middle line:84%
ERIK DEMAINE: No,
to alphabetize--

00:33:24.650 --> 00:33:27.230 align:middle line:84%
we do want to, in the end,
sort by the first letter.

00:33:27.230 --> 00:33:29.150 align:middle line:90%
But that's at the end.

00:33:29.150 --> 00:33:30.690 align:middle line:84%
So at the end--
remember, radix sort

00:33:30.690 --> 00:33:32.690 align:middle line:84%
always goes backwards
from the least significant

00:33:32.690 --> 00:33:34.340 align:middle line:90%
to the most significant.

00:33:34.340 --> 00:33:36.090 align:middle line:84%
And so indeed, that
is what we want to do.

00:33:36.090 --> 00:33:37.250 align:middle line:84%
You're just saying,
use radix sort.

00:33:37.250 --> 00:33:38.690 align:middle line:90%
But what am I radix sort on?

00:33:38.690 --> 00:33:41.150 align:middle line:90%
What am I radix sorting on?

00:33:41.150 --> 00:33:44.353 align:middle line:84%
AUDIENCE: Yeah, on the last
letters, not the first letters.

00:33:44.353 --> 00:33:45.770 align:middle line:84%
ERIK DEMAINE: So
technically, that

00:33:45.770 --> 00:33:47.953 align:middle line:84%
would be using counting
sort on the last letter,

00:33:47.953 --> 00:33:49.870 align:middle line:84%
counting sort of the
next to last letter, dot,

00:33:49.870 --> 00:33:53.330 align:middle line:84%
dot, dot, counting sort
on the first letter.

00:33:53.330 --> 00:33:56.510 align:middle line:84%
But that is, together,
radix sort on something,

00:33:56.510 --> 00:34:01.580 align:middle line:84%
or Jason likes to call
this tuple sorting.

00:34:01.580 --> 00:34:03.150 align:middle line:90%
Tuple sort is the thing--

00:34:03.150 --> 00:34:05.600 align:middle line:84%
is the algorithm that says,
sort by the last thing,

00:34:05.600 --> 00:34:08.580 align:middle line:84%
then sort by the previous
thing, and so on.

00:34:08.580 --> 00:34:10.820 align:middle line:84%
You can also think of
this as radix sorting

00:34:10.820 --> 00:34:13.025 align:middle line:90%
on a number written in base 26.

00:34:13.025 --> 00:34:15.550 align:middle line:90%


00:34:15.550 --> 00:34:16.639 align:middle line:90%
They're the same thing.

00:34:16.639 --> 00:34:24.440 align:middle line:90%


00:34:24.440 --> 00:34:28.227 align:middle line:84%
But in the end, we can
sort in linear time.

00:34:28.227 --> 00:34:30.830 align:middle line:84%
AUDIENCE: How do you
ensure that the letters are

00:34:30.830 --> 00:34:33.818 align:middle line:90%
sorted in order, though?

00:34:33.818 --> 00:34:36.975 align:middle line:84%
Like, how do you ensure that--
how do you tell the algorithm

00:34:36.975 --> 00:34:39.850 align:middle line:90%
that you want A to come--

00:34:39.850 --> 00:34:42.596 align:middle line:84%
just like not-- 0 is less
than 1, A is less than B.

00:34:42.596 --> 00:34:43.429 align:middle line:90%
ERIK DEMAINE: Right.

00:34:43.429 --> 00:34:45.230 align:middle line:84%
So I mean, technically,
when you call

00:34:45.230 --> 00:34:47.270 align:middle line:90%
something like tuple sort--

00:34:47.270 --> 00:34:49.810 align:middle line:84%
or maybe it's even clearer
when you call radix sort.

00:34:49.810 --> 00:34:51.810 align:middle line:84%
Radix sort, you're giving
it a bunch of numbers.

00:34:51.810 --> 00:34:55.560 align:middle line:84%
So you're taking these strings
and mapping them to numbers.

00:34:55.560 --> 00:34:57.775 align:middle line:84%
And when you do that, you
get to decide which letter

00:34:57.775 --> 00:34:59.150 align:middle line:84%
is the most
significant, which is

00:34:59.150 --> 00:35:01.100 align:middle line:90%
the least significant, right?

00:35:01.100 --> 00:35:04.700 align:middle line:84%
So you will choose to always map
the first letter in your string

00:35:04.700 --> 00:35:07.250 align:middle line:90%
to position--

00:35:07.250 --> 00:35:13.130 align:middle line:84%
to value, or the--
what do you call it?

00:35:13.130 --> 00:35:15.050 align:middle line:90%
Position in positional notation.

00:35:15.050 --> 00:35:19.590 align:middle line:84%
Position 26 to the power 10
log n as the most significant.

00:35:19.590 --> 00:35:21.090 align:middle line:84%
So it's always the
most significant.

00:35:21.090 --> 00:35:22.580 align:middle line:84%
Even if your string
is of length 1,

00:35:22.580 --> 00:35:25.070 align:middle line:84%
you want to put that in
the most significant digit.

00:35:25.070 --> 00:35:26.870 align:middle line:84%
And you'll pad with
zeros at the end

00:35:26.870 --> 00:35:29.340 align:middle line:84%
if you run out of
letters in your string.

00:35:29.340 --> 00:35:31.970 align:middle line:84%
AUDIENCE: How many times are
you running counting sort here?

00:35:31.970 --> 00:35:34.303 align:middle line:84%
ERIK DEMAINE: How many times
am I running counting sort?

00:35:34.303 --> 00:35:35.680 align:middle line:90%
Oh, 10 log n times.

00:35:35.680 --> 00:35:36.775 align:middle line:90%
Whoops.

00:35:36.775 --> 00:35:37.880 align:middle line:90%
Yeah, good question.

00:35:37.880 --> 00:35:39.240 align:middle line:90%
Good point.

00:35:39.240 --> 00:35:40.890 align:middle line:90%
Yeah, I computed this wrong.

00:35:40.890 --> 00:35:42.980 align:middle line:90%
So right.

00:35:42.980 --> 00:35:47.180 align:middle line:84%
There are log n
digits in the string.

00:35:47.180 --> 00:35:49.310 align:middle line:90%
So that is bad.

00:35:49.310 --> 00:35:51.270 align:middle line:90%
I mean, it's OK.

00:35:51.270 --> 00:35:57.480 align:middle line:84%
We'll end up with n log n
running time by the tuple sort.

00:35:57.480 --> 00:36:01.850 align:middle line:90%


00:36:01.850 --> 00:36:03.920 align:middle line:84%
However-- so that's
the tuple sort.

00:36:03.920 --> 00:36:07.380 align:middle line:84%
So I should really make
this not equivalent.

00:36:07.380 --> 00:36:10.410 align:middle line:84%
If I run tuple short letter
by letter, I'm going to do--

00:36:10.410 --> 00:36:12.270 align:middle line:84%
I'm running counting
sort log n times.

00:36:12.270 --> 00:36:16.310 align:middle line:84%
And so I get n log n, because
each one takes linear time.

00:36:16.310 --> 00:36:20.630 align:middle line:84%
If I map my strings
into numbers first,

00:36:20.630 --> 00:36:22.355 align:middle line:90%
radix sort doesn't use base 26.

00:36:22.355 --> 00:36:24.500 align:middle line:90%
It uses base n.

00:36:24.500 --> 00:36:28.070 align:middle line:84%
And then it will
only run 10 times,

00:36:28.070 --> 00:36:38.520 align:middle line:84%
because 2 to the 10
log n is n to the 10.

00:36:38.520 --> 00:36:42.800 align:middle line:84%
And so the numbers that we're
sorting are between 0 and n

00:36:42.800 --> 00:36:44.040 align:middle line:90%
to the 10.

00:36:44.040 --> 00:36:46.290 align:middle line:90%
And so u is n to the 10.

00:36:46.290 --> 00:36:49.380 align:middle line:84%
And so that's the case when
radix sort runs in linear time.

00:36:49.380 --> 00:36:53.210 align:middle line:84%
So if you run tuple short
letter by letter, it's slow.

00:36:53.210 --> 00:36:55.700 align:middle line:84%
If you run radix sort,
it's doing a whole bunch

00:36:55.700 --> 00:36:56.720 align:middle line:90%
of letters at once.

00:36:56.720 --> 00:36:58.340 align:middle line:84%
Effectively, it's
doing log n letters

00:36:58.340 --> 00:37:01.700 align:middle line:84%
at a time in a single
call to counting sort.

00:37:01.700 --> 00:37:05.930 align:middle line:84%
And so the radix sort will
actually win and get linear.

00:37:05.930 --> 00:37:09.883 align:middle line:90%


00:37:09.883 --> 00:37:11.300 align:middle line:84%
There's a subtlety
here, which is,

00:37:11.300 --> 00:37:13.940 align:middle line:84%
I'm assuming that we can
actually take these strings

00:37:13.940 --> 00:37:18.380 align:middle line:84%
and convert them into integers
in constant time each.

00:37:18.380 --> 00:37:20.750 align:middle line:84%
And this problem
set was ambiguous.

00:37:20.750 --> 00:37:22.610 align:middle line:90%
And both answers were accepted.

00:37:22.610 --> 00:37:25.010 align:middle line:84%
If you assume these letters
are nice and compactly

00:37:25.010 --> 00:37:27.800 align:middle line:84%
stored, and they
fit in 10 words,

00:37:27.800 --> 00:37:31.280 align:middle line:84%
because a word is at
least log n bits long,

00:37:31.280 --> 00:37:33.560 align:middle line:90%
then you can actually do this.

00:37:33.560 --> 00:37:36.650 align:middle line:84%
If you store each letter
in a separate word,

00:37:36.650 --> 00:37:40.496 align:middle line:84%
then just reading the entire
input will take n log n time.

00:37:40.496 --> 00:37:44.947 align:middle line:84%
So that's a subtlety which we
don't need to worry too much

00:37:44.947 --> 00:37:45.780 align:middle line:90%
about in this class.

00:37:45.780 --> 00:37:46.280 align:middle line:90%
Yeah?

00:37:46.280 --> 00:37:49.340 align:middle line:84%
AUDIENCE: So [INAUDIBLE]
bounding the letters

00:37:49.340 --> 00:37:50.312 align:middle line:90%
to numbers.

00:37:50.312 --> 00:37:52.267 align:middle line:90%
And like, how would that help?

00:37:52.267 --> 00:37:55.130 align:middle line:90%
Because we still have to do 26--

00:37:55.130 --> 00:37:58.340 align:middle line:84%
ERIK DEMAINE: Yeah, there
are 26 possible letters,

00:37:58.340 --> 00:38:01.260 align:middle line:90%
numbering them 0 to 25.

00:38:01.260 --> 00:38:05.450 align:middle line:84%
And then when we take
a string, like AA,

00:38:05.450 --> 00:38:09.740 align:middle line:90%
we map this into 00 in base 26.

00:38:09.740 --> 00:38:12.350 align:middle line:90%


00:38:12.350 --> 00:38:13.430 align:middle line:90%
That's a number.

00:38:13.430 --> 00:38:18.350 align:middle line:84%
If we do BB, for
example, this maps to 11

00:38:18.350 --> 00:38:25.820 align:middle line:84%
in base 26, which means 1
times 26 plus 1, which is 27.

00:38:25.820 --> 00:38:28.958 align:middle line:84%
OK, so that's the
mapping that I mean.

00:38:28.958 --> 00:38:31.250 align:middle line:84%
AUDIENCE: You're mapping the
whole string [INAUDIBLE]??

00:38:31.250 --> 00:38:34.130 align:middle line:84%
ERIK DEMAINE: The whole string
to a single number, yeah.

00:38:34.130 --> 00:38:36.740 align:middle line:84%
And there's a subtlety,
because I want lexicographic.

00:38:36.740 --> 00:38:38.540 align:middle line:84%
I need to pad things
with spaces at the end

00:38:38.540 --> 00:38:40.850 align:middle line:84%
or pad them with As
at the end in case

00:38:40.850 --> 00:38:44.410 align:middle line:90%
they're shorter than 10 log n.

00:38:44.410 --> 00:38:46.150 align:middle line:90%
OK, cool.

00:38:46.150 --> 00:38:46.990 align:middle line:90%
That was b.

00:38:46.990 --> 00:38:50.330 align:middle line:90%


00:38:50.330 --> 00:38:52.610 align:middle line:90%
c is not very interesting.

00:38:52.610 --> 00:39:00.410 align:middle line:84%
It's integers in the
range 0 to n squared.

00:39:00.410 --> 00:39:02.420 align:middle line:84%
This, I can just
solve with radix sort,

00:39:02.420 --> 00:39:03.990 align:middle line:84%
because my radix
sort, at this point,

00:39:03.990 --> 00:39:06.160 align:middle line:90%
we've done it a third time.

00:39:06.160 --> 00:39:09.050 align:middle line:84%
Radix sort, we can sort as
long as the integers are

00:39:09.050 --> 00:39:10.400 align:middle line:90%
bounded by a polynomial.

00:39:10.400 --> 00:39:13.940 align:middle line:84%
Here, it's a fixed polynomial
with a constant exponent.

00:39:13.940 --> 00:39:16.370 align:middle line:84%
So this will-- and
this is radix sort,

00:39:16.370 --> 00:39:19.220 align:middle line:84%
like we saw, that just
calls counting sort twice,

00:39:19.220 --> 00:39:21.290 align:middle line:90%
linear time.

00:39:21.290 --> 00:39:24.240 align:middle line:84%
d is where things
get more interesting.

00:39:24.240 --> 00:39:29.100 align:middle line:84%
Let me get this
phrasing the same.

00:39:29.100 --> 00:39:36.230 align:middle line:84%
So in d, we have rational
numbers of the form w over f.

00:39:36.230 --> 00:39:40.310 align:middle line:90%
This is some win ratio.

00:39:40.310 --> 00:39:42.230 align:middle line:90%
Always in the range 0 to 1.

00:39:42.230 --> 00:39:44.420 align:middle line:90%
So we saw w is at most f.

00:39:44.420 --> 00:39:49.550 align:middle line:84%
And 0 is less than w, is
less than f, is less than n

00:39:49.550 --> 00:39:51.380 align:middle line:90%
squared, because the--

00:39:51.380 --> 00:39:53.185 align:middle line:90%
that is really confusing--

00:39:53.185 --> 00:39:55.920 align:middle line:90%


00:39:55.920 --> 00:39:57.470 align:middle line:90%
is less than n squared--

00:39:57.470 --> 00:40:00.200 align:middle line:90%
those are separate statements--

00:40:00.200 --> 00:40:02.240 align:middle line:84%
because the f actually
comes from part c.

00:40:02.240 --> 00:40:04.800 align:middle line:84%
And c is really a
setup for this one.

00:40:04.800 --> 00:40:06.770 align:middle line:84%
Doesn't really matter
what this means.

00:40:06.770 --> 00:40:09.050 align:middle line:84%
It's just that we
have numbers w and f,

00:40:09.050 --> 00:40:10.460 align:middle line:90%
where w is always less than f.

00:40:10.460 --> 00:40:12.420 align:middle line:84%
And they're between
0 and n squared.

00:40:12.420 --> 00:40:15.500 align:middle line:84%
So you should think, this is
a good range for me, right?

00:40:15.500 --> 00:40:17.240 align:middle line:84%
That I'm representing
this rational

00:40:17.240 --> 00:40:19.650 align:middle line:84%
in terms of two numbers
between 0 and n squared.

00:40:19.650 --> 00:40:22.700 align:middle line:84%
So there's like n to
the 4th possible choices

00:40:22.700 --> 00:40:24.500 align:middle line:90%
for what w and f are.

00:40:24.500 --> 00:40:26.780 align:middle line:84%
So the range of my
values is n to the 4th.

00:40:26.780 --> 00:40:29.780 align:middle line:84%
That's the setting where
radix sort should run fast.

00:40:29.780 --> 00:40:33.290 align:middle line:84%
Unfortunately, these numbers--
what I want to sort by

00:40:33.290 --> 00:40:34.500 align:middle line:90%
is not an integer.

00:40:34.500 --> 00:40:36.650 align:middle line:90%
It's a rational.

00:40:36.650 --> 00:40:39.020 align:middle line:90%
And that's annoying.

00:40:39.020 --> 00:40:43.850 align:middle line:84%
So there are a couple of
ways to solve this problem.

00:40:43.850 --> 00:40:48.980 align:middle line:84%
In general, a good way to solve
sorting is to use merge sort.

00:40:48.980 --> 00:40:50.590 align:middle line:84%
Merge sort is always
a good answer.

00:40:50.590 --> 00:40:51.770 align:middle line:90%
It's not the best answer.

00:40:51.770 --> 00:40:54.540 align:middle line:84%
In these cases, we
shaved off a log.

00:40:54.540 --> 00:40:55.730 align:middle line:90%
We got to linear time.

00:40:55.730 --> 00:40:57.330 align:middle line:90%
But n log n is pretty good.

00:40:57.330 --> 00:40:58.530 align:middle line:90%
It's pretty close to n.

00:40:58.530 --> 00:41:01.820 align:middle line:84%
So first goal might
be, can we even achieve

00:41:01.820 --> 00:41:03.428 align:middle line:90%
n log n via merge sort?

00:41:03.428 --> 00:41:06.710 align:middle line:90%


00:41:06.710 --> 00:41:13.805 align:middle line:84%
What would I need to do in order
to actually apply merge sort

00:41:13.805 --> 00:41:14.840 align:middle line:90%
to this instance?

00:41:14.840 --> 00:41:18.700 align:middle line:90%


00:41:18.700 --> 00:41:21.690 align:middle line:84%
What does merge
sort do to its keys?

00:41:21.690 --> 00:41:32.110 align:middle line:90%


00:41:32.110 --> 00:41:32.610 align:middle line:90%
Sorry?

00:41:32.610 --> 00:41:34.230 align:middle line:84%
AUDIENCE: Isolate
and compare them.

00:41:34.230 --> 00:41:36.930 align:middle line:84%
ERIK DEMAINE: It isolates and
compares them, yeah, right.

00:41:36.930 --> 00:41:39.030 align:middle line:84%
So there's an array
data structure.

00:41:39.030 --> 00:41:40.410 align:middle line:90%
And it indexes into the array.

00:41:40.410 --> 00:41:41.820 align:middle line:90%
That's the isolation.

00:41:41.820 --> 00:41:45.330 align:middle line:84%
But then the thing it actually
does with the items themselves

00:41:45.330 --> 00:41:46.427 align:middle line:90%
is always a comparison.

00:41:46.427 --> 00:41:48.510 align:middle line:84%
And this is why we introduced
the comparison model

00:41:48.510 --> 00:41:51.150 align:middle line:84%
and proved an n log n lower
bound in the comparison model,

00:41:51.150 --> 00:41:53.010 align:middle line:84%
because merge sort,
and insertion sort,

00:41:53.010 --> 00:41:55.920 align:middle line:84%
and selection sort are
all comparison algorithms.

00:41:55.920 --> 00:41:57.443 align:middle line:90%
Radix sort is not.

00:41:57.443 --> 00:41:58.110 align:middle line:90%
But this one is.

00:41:58.110 --> 00:42:03.150 align:middle line:84%
But to apply merge sort, I need
to say, how do I compare wi

00:42:03.150 --> 00:42:09.375 align:middle line:90%
over fi versus wj over fj?

00:42:09.375 --> 00:42:12.850 align:middle line:90%


00:42:12.850 --> 00:42:15.580 align:middle line:84%
My computer only
deals with integers.

00:42:15.580 --> 00:42:19.090 align:middle line:84%
We can't actually
represent wi over fi

00:42:19.090 --> 00:42:23.710 align:middle line:84%
explicitly in binary, because
it has infinitely many bits.

00:42:23.710 --> 00:42:25.240 align:middle line:84%
But I can represent
it implicitly

00:42:25.240 --> 00:42:27.080 align:middle line:90%
by storing wi and fi.

00:42:27.080 --> 00:42:27.580 align:middle line:90%
Yeah?

00:42:27.580 --> 00:42:29.620 align:middle line:90%
AUDIENCE: Multiply by fi and fj.

00:42:29.620 --> 00:42:31.570 align:middle line:84%
ERIK DEMAINE: Multiply
by fi and fj, yeah.

00:42:31.570 --> 00:42:33.220 align:middle line:84%
When I went-- I
didn't go to school,

00:42:33.220 --> 00:42:37.123 align:middle line:84%
but then we learned
cross multiplication,

00:42:37.123 --> 00:42:39.165 align:middle line:84%
which is the same as
multiplying both sides by fi

00:42:39.165 --> 00:42:41.530 align:middle line:84%
and multiplying both
sides by fj, as you said.

00:42:41.530 --> 00:42:48.880 align:middle line:84%
So then we get fi fj less
than question mark f--

00:42:48.880 --> 00:42:53.433 align:middle line:90%
whatever-- fi wj.

00:42:53.433 --> 00:42:55.600 align:middle line:84%
When we do that, we better
make sure that the things

00:42:55.600 --> 00:42:57.183 align:middle line:84%
we're multiplying
by are non-negative.

00:42:57.183 --> 00:42:58.750 align:middle line:90%
Otherwise, the sign flips.

00:42:58.750 --> 00:43:01.870 align:middle line:84%
But here, we assume
they're all non-negative.

00:43:01.870 --> 00:43:02.988 align:middle line:90%
So this is good.

00:43:02.988 --> 00:43:05.030 align:middle line:84%
And now we're just
multiplying two integers here,

00:43:05.030 --> 00:43:06.970 align:middle line:84%
multiplying two integers
here, and comparing.

00:43:06.970 --> 00:43:08.803 align:middle line:84%
Those are all things I
can do in a word RAM.

00:43:08.803 --> 00:43:11.440 align:middle line:90%


00:43:11.440 --> 00:43:13.600 align:middle line:84%
So this was actually
the intended solution

00:43:13.600 --> 00:43:14.980 align:middle line:90%
when this problem was posed.

00:43:14.980 --> 00:43:16.510 align:middle line:84%
Here's a way to do
comparison sort.

00:43:16.510 --> 00:43:17.890 align:middle line:90%
We get n log n.

00:43:17.890 --> 00:43:21.140 align:middle line:84%
But in fact, you can
achieve linear time.

00:43:21.140 --> 00:43:21.640 align:middle line:90%
Yeah?

00:43:21.640 --> 00:43:23.723 align:middle line:84%
AUDIENCE: [INAUDIBLE] that
solution, how would you

00:43:23.723 --> 00:43:26.110 align:middle line:90%
quickly say which one's bigger?

00:43:26.110 --> 00:43:29.573 align:middle line:84%
Because wi times f
of j, one of them

00:43:29.573 --> 00:43:32.320 align:middle line:84%
belongs to one of the
Pokemons, and the other one

00:43:32.320 --> 00:43:34.852 align:middle line:90%
is [INAUDIBLE].

00:43:34.852 --> 00:43:37.060 align:middle line:84%
ERIK DEMAINE: I feel like
there's a joke here, like--

00:43:37.060 --> 00:43:38.523 align:middle line:90%
AUDIENCE: [INAUDIBLE]

00:43:38.523 --> 00:43:39.940 align:middle line:84%
ERIK DEMAINE:
Pikachu is superior.

00:43:39.940 --> 00:43:42.860 align:middle line:90%
That's always the answer.

00:43:42.860 --> 00:43:44.950 align:middle line:84%
So how do I tell
whether one Pokemon

00:43:44.950 --> 00:43:46.730 align:middle line:90%
is superior to the other?

00:43:46.730 --> 00:43:51.510 align:middle line:90%
If I multiply my--

00:43:51.510 --> 00:43:56.020 align:middle line:84%
I multiply i's f value
with j's w value.

00:43:56.020 --> 00:43:59.890 align:middle line:84%
And I see whether that's
greater than i's w

00:43:59.890 --> 00:44:02.510 align:middle line:90%
value times j's f value.

00:44:02.510 --> 00:44:03.830 align:middle line:90%
And if it is--

00:44:03.830 --> 00:44:06.718 align:middle line:90%
so these are equivalent.

00:44:06.718 --> 00:44:08.260 align:middle line:84%
If this one is
greater than this one,

00:44:08.260 --> 00:44:10.180 align:middle line:84%
I know that this is
greater than this.

00:44:10.180 --> 00:44:14.350 align:middle line:84%
These are equivalent sentences
by mathematics, by algebra.

00:44:14.350 --> 00:44:16.630 align:middle line:84%
And so this is what
I want to know.

00:44:16.630 --> 00:44:18.760 align:middle line:84%
This would say j
is superior to i.

00:44:18.760 --> 00:44:22.010 align:middle line:84%
And so I determine that
by actually doing this.

00:44:22.010 --> 00:44:25.060 align:middle line:84%
So then I don't have to divide
and deal with real numbers,

00:44:25.060 --> 00:44:27.790 align:middle line:84%
because I don't know how,
because I'm a computer.

00:44:27.790 --> 00:44:31.110 align:middle line:90%


00:44:31.110 --> 00:44:32.430 align:middle line:90%
We're all computers in the end.

00:44:32.430 --> 00:44:39.345 align:middle line:90%


00:44:39.345 --> 00:44:39.845 align:middle line:90%
OK.

00:44:39.845 --> 00:44:53.050 align:middle line:90%


00:44:53.050 --> 00:44:57.100 align:middle line:84%
So it would be great
if my numbers all

00:44:57.100 --> 00:44:58.670 align:middle line:90%
had the same denominator.

00:44:58.670 --> 00:45:02.530 align:middle line:84%
If they all had the same f, then
I could just compare the w's.

00:45:02.530 --> 00:45:06.220 align:middle line:84%
So that's one intuition
for why we can actually

00:45:06.220 --> 00:45:09.070 align:middle line:90%
do this in linear time.

00:45:09.070 --> 00:45:11.440 align:middle line:84%
But the way I like to
think about it-- so let's

00:45:11.440 --> 00:45:16.240 align:middle line:84%
just draw the real
interval from 0 to 1.

00:45:16.240 --> 00:45:23.040 align:middle line:84%
And there are various spots
all over here that represent--

00:45:23.040 --> 00:45:24.310 align:middle line:90%
I can't actually compute this.

00:45:24.310 --> 00:45:27.310 align:middle line:84%
But conceptually, each of
these wi fi's falls somewhere

00:45:27.310 --> 00:45:29.790 align:middle line:90%
in that interval from 0 to 1.

00:45:29.790 --> 00:45:34.012 align:middle line:90%
And I want to sort them somehow.

00:45:34.012 --> 00:45:35.470 align:middle line:84%
So one thing that
would be great is

00:45:35.470 --> 00:45:37.030 align:middle line:84%
if I could take
these real numbers

00:45:37.030 --> 00:45:42.830 align:middle line:84%
and somehow map
them to integers,

00:45:42.830 --> 00:45:47.560 align:middle line:84%
which are uniformly spaced,
maybe a few more of them.

00:45:47.560 --> 00:45:50.620 align:middle line:84%
But these go from
0 to u minus 1.

00:45:50.620 --> 00:45:53.080 align:middle line:84%
And if I could get
u relatively small,

00:45:53.080 --> 00:45:55.550 align:middle line:90%
and I could map each of these--

00:45:55.550 --> 00:45:58.450 align:middle line:84%
so I want that mapping
to be order preserving.

00:45:58.450 --> 00:46:03.160 align:middle line:84%
And I want two very close,
but distinct items to map to--

00:46:03.160 --> 00:46:04.600 align:middle line:90%
distinct keys here.

00:46:04.600 --> 00:46:06.760 align:middle line:84%
I want them to map to
distinct integers down here.

00:46:06.760 --> 00:46:08.968 align:middle line:84%
If I could do that, then I
just sort by the integers.

00:46:08.968 --> 00:46:13.070 align:middle line:84%
And that's the same as
sorting by the real numbers.

00:46:13.070 --> 00:46:17.650 align:middle line:84%
And so at this point,
I wonder, how close

00:46:17.650 --> 00:46:20.350 align:middle line:90%
can two of these numbers be?

00:46:20.350 --> 00:46:30.010 align:middle line:90%
So how close can two keys be?

00:46:30.010 --> 00:46:37.510 align:middle line:84%
So I want to consider wi
over fi minus wj over fj

00:46:37.510 --> 00:46:38.580 align:middle line:90%
in absolute value.

00:46:38.580 --> 00:46:41.110 align:middle line:90%


00:46:41.110 --> 00:46:43.550 align:middle line:90%
Now I do algebra.

00:46:43.550 --> 00:46:44.830 align:middle line:90%
So this is--

00:46:44.830 --> 00:46:47.900 align:middle line:84%
I'd like to bring
this into one ratio.

00:46:47.900 --> 00:46:49.090 align:middle line:90%
So this is--

00:46:49.090 --> 00:46:52.782 align:middle line:84%
I can do that by multiplying
1 by fi, 1 by fj.

00:46:52.782 --> 00:46:58.360 align:middle line:84%
Now that's wi fj minus
wj fi, which should

00:46:58.360 --> 00:47:01.030 align:middle line:90%
look a lot like something here.

00:47:01.030 --> 00:47:02.740 align:middle line:90%
But never mind.

00:47:02.740 --> 00:47:04.520 align:middle line:84%
I'm sure there's a
deep connection here.

00:47:04.520 --> 00:47:08.430 align:middle line:84%
I can probably use this to
prove that and vice versa.

00:47:08.430 --> 00:47:08.930 align:middle line:90%
Cool.

00:47:08.930 --> 00:47:11.980 align:middle line:84%
So with some absolute
values, same thing.

00:47:11.980 --> 00:47:15.160 align:middle line:84%
Maybe these are non-negative,
so I can actually

00:47:15.160 --> 00:47:18.220 align:middle line:84%
just put absolute
values on the top part.

00:47:18.220 --> 00:47:24.070 align:middle line:84%
And OK, wi is an integer, fj is
an integer, wj is an integer,

00:47:24.070 --> 00:47:27.310 align:middle line:84%
fi is an integer, all
greater than or equal to 0.

00:47:27.310 --> 00:47:30.560 align:middle line:90%
So this thing is an integer.

00:47:30.560 --> 00:47:33.405 align:middle line:90%
So it could be equal to 0.

00:47:33.405 --> 00:47:35.530 align:middle line:84%
It's a non-negative integer,
because all the things

00:47:35.530 --> 00:47:36.400 align:middle line:90%
are non-negative.

00:47:36.400 --> 00:47:37.390 align:middle line:90%
It could be equal to 0.

00:47:37.390 --> 00:47:38.765 align:middle line:84%
But if they're
equal to 0, that's

00:47:38.765 --> 00:47:41.590 align:middle line:84%
actually identical
ratios, right?

00:47:41.590 --> 00:47:43.240 align:middle line:84%
If this is 0, the
whole thing is 0.

00:47:43.240 --> 00:47:46.180 align:middle line:84%
And so these two
values were the same.

00:47:46.180 --> 00:47:47.560 align:middle line:84%
OK, but let's
suppose it's not 0.

00:47:47.560 --> 00:47:50.170 align:middle line:84%
If it's not 0, it's
actually at least 1,

00:47:50.170 --> 00:47:53.950 align:middle line:84%
the absolute value,
because it's an integer.

00:47:53.950 --> 00:47:55.210 align:middle line:90%
What about the bottom?

00:47:55.210 --> 00:47:57.950 align:middle line:90%
fi-- so now we want this--

00:47:57.950 --> 00:48:00.040 align:middle line:84%
I want to know how
small this ratio can be.

00:48:00.040 --> 00:48:02.860 align:middle line:84%
It's going to be small when
this is small and this is big.

00:48:02.860 --> 00:48:05.030 align:middle line:90%
How big could fi fj be?

00:48:05.030 --> 00:48:07.720 align:middle line:84%
Well, we're told that all the
f's are less than n squared.

00:48:07.720 --> 00:48:10.610 align:middle line:84%
So this thing is
at most n squared,

00:48:10.610 --> 00:48:14.380 align:middle line:84%
n to the 4th, less
than n the 4th--

00:48:14.380 --> 00:48:17.620 align:middle line:84%
n squared minus 1 squared,
less than n to the 4th.

00:48:17.620 --> 00:48:20.050 align:middle line:90%
AUDIENCE: [INAUDIBLE]

00:48:20.050 --> 00:48:21.910 align:middle line:84%
ERIK DEMAINE: fi is
at most n squared.

00:48:21.910 --> 00:48:24.230 align:middle line:90%
fj is at most n squared.

00:48:24.230 --> 00:48:26.450 align:middle line:90%
So it's n squared squared.

00:48:26.450 --> 00:48:29.570 align:middle line:84%
So this is at least
1 over n to the 4th.

00:48:29.570 --> 00:48:32.830 align:middle line:84%
So the closest the two
points can get here

00:48:32.830 --> 00:48:34.810 align:middle line:90%
is 1 over n to the 4th.

00:48:34.810 --> 00:48:39.430 align:middle line:84%
So what can I do to scale
that up to make them

00:48:39.430 --> 00:48:41.860 align:middle line:90%
kind of like integers?

00:48:41.860 --> 00:48:45.400 align:middle line:90%
Multiply by n to the 4th.

00:48:45.400 --> 00:48:54.220 align:middle line:84%
So just multiply by n to
the 4th and then floor.

00:48:54.220 --> 00:48:59.170 align:middle line:84%
So we're going to
take each fi over--

00:48:59.170 --> 00:49:00.640 align:middle line:90%
I'd like to compute this ratio.

00:49:00.640 --> 00:49:02.110 align:middle line:90%
But I don't know how.

00:49:02.110 --> 00:49:05.320 align:middle line:84%
So instead, I'm going
to take fi, multiply--

00:49:05.320 --> 00:49:05.890 align:middle line:90%
OK.

00:49:05.890 --> 00:49:08.890 align:middle line:84%
Conceptually, what I want to
do is multiply by n to the 4th

00:49:08.890 --> 00:49:10.510 align:middle line:90%
and take the floor.

00:49:10.510 --> 00:49:16.840 align:middle line:84%
How do I actually do this
in a machine that doesn't

00:49:16.840 --> 00:49:18.310 align:middle line:90%
have real numbers like this?

00:49:18.310 --> 00:49:20.900 align:middle line:90%


00:49:20.900 --> 00:49:23.575 align:middle line:84%
So I don't have a
floor operation.

00:49:23.575 --> 00:49:26.200 align:middle line:90%
I just have integer operations.

00:49:26.200 --> 00:49:36.610 align:middle line:84%
Then I can take fi,
multiply it by n to the 4th,

00:49:36.610 --> 00:49:38.450 align:middle line:90%
and integer divide by wj.

00:49:38.450 --> 00:49:41.290 align:middle line:90%


00:49:41.290 --> 00:49:42.400 align:middle line:90%
That is the same--

00:49:42.400 --> 00:49:45.160 align:middle line:84%
that computes exactly
this, because I

00:49:45.160 --> 00:49:46.910 align:middle line:84%
can do the multiplication
and the division

00:49:46.910 --> 00:49:50.192 align:middle line:90%
in either order in real space.

00:49:50.192 --> 00:49:52.400 align:middle line:84%
And then this does the floor
at the appropriate time.

00:49:52.400 --> 00:49:54.620 align:middle line:84%
But this is just
operations on integers.

00:49:54.620 --> 00:49:57.010 align:middle line:84%
And now these are
integers representing

00:49:57.010 --> 00:49:59.080 align:middle line:90%
how good my Pokemon are.

00:49:59.080 --> 00:50:02.110 align:middle line:84%
They have the property that
any two distinct ones--

00:50:02.110 --> 00:50:04.690 align:middle line:84%
before I take the floor, any
two distinct ones are at least 1

00:50:04.690 --> 00:50:05.493 align:middle line:90%
apart.

00:50:05.493 --> 00:50:07.660 align:middle line:84%
So after I take the floor,
they will remain 1 apart.

00:50:07.660 --> 00:50:09.760 align:middle line:84%
They will remain
distinct integers.

00:50:09.760 --> 00:50:12.430 align:middle line:84%
And so I have successfully
mapped my real numbers

00:50:12.430 --> 00:50:14.710 align:middle line:84%
to integers where distinct
real numbers match

00:50:14.710 --> 00:50:15.590 align:middle line:90%
distinct integers.

00:50:15.590 --> 00:50:16.090 align:middle line:90%
Yeah?

00:50:16.090 --> 00:50:16.715 align:middle line:90%
AUDIENCE: Wait.

00:50:16.715 --> 00:50:18.870 align:middle line:84%
So why is fi now in
the numerator, and wi

00:50:18.870 --> 00:50:19.760 align:middle line:90%
in the denominator?

00:50:19.760 --> 00:50:21.010 align:middle line:90%
ERIK DEMAINE: Did I flip them?

00:50:21.010 --> 00:50:22.450 align:middle line:90%
Yeah, sorry.

00:50:22.450 --> 00:50:26.620 align:middle line:84%
Please invert
everything-- just here.

00:50:26.620 --> 00:50:27.670 align:middle line:90%
This is w and fi.

00:50:27.670 --> 00:50:28.630 align:middle line:90%
That was just a typo.

00:50:28.630 --> 00:50:33.390 align:middle line:90%


00:50:33.390 --> 00:50:35.016 align:middle line:90%
That's all of them.

00:50:35.016 --> 00:50:36.480 align:middle line:90%
OK.

00:50:36.480 --> 00:50:38.200 align:middle line:84%
AUDIENCE: Are they
both i's or j's?

00:50:38.200 --> 00:50:41.840 align:middle line:90%


00:50:41.840 --> 00:50:45.310 align:middle line:84%
ERIK DEMAINE: These are
supposed to both be i's, yeah.

00:50:45.310 --> 00:50:46.410 align:middle line:90%
Thank you.

00:50:46.410 --> 00:50:49.680 align:middle line:84%
This was for each
Pokemon, i, we're

00:50:49.680 --> 00:50:52.595 align:middle line:84%
going to compute
this as our key.

00:50:52.595 --> 00:50:54.720 align:middle line:84%
And then we're going to
sort by those integer keys.

00:50:54.720 --> 00:50:56.678 align:middle line:84%
And that will sort the
Pokemon by their ratios.

00:50:56.678 --> 00:51:00.930 align:middle line:90%


00:51:00.930 --> 00:51:05.080 align:middle line:90%
Let's write mon for monster.

00:51:05.080 --> 00:51:05.580 align:middle line:90%
Yeah?

00:51:05.580 --> 00:51:10.560 align:middle line:84%
AUDIENCE: [INAUDIBLE]
u minus 1 [INAUDIBLE]??

00:51:10.560 --> 00:51:12.960 align:middle line:90%
ERIK DEMAINE: So u was just a--

00:51:12.960 --> 00:51:16.028 align:middle line:84%
sorry, this is-- a label on
this thing might help you.

00:51:16.028 --> 00:51:16.570 align:middle line:90%
AUDIENCE: Oh.

00:51:16.570 --> 00:51:19.050 align:middle line:90%
ERIK DEMAINE: Yeah.

00:51:19.050 --> 00:51:21.720 align:middle line:90%
So now my u-- oh, right.

00:51:21.720 --> 00:51:23.110 align:middle line:90%
What is my u?

00:51:23.110 --> 00:51:24.480 align:middle line:90%
What is my largest key?

00:51:24.480 --> 00:51:32.048 align:middle line:90%


00:51:32.048 --> 00:51:36.145 align:middle line:84%
It occurs to me, I really would
like fi to be bigger than 0.

00:51:36.145 --> 00:51:40.540 align:middle line:90%
But let's not worry about it.

00:51:40.540 --> 00:51:42.040 align:middle line:90%
How big can u be?

00:51:42.040 --> 00:51:45.410 align:middle line:84%
Well, the biggest this
can be is if fi is small,

00:51:45.410 --> 00:51:46.240 align:middle line:90%
and this is big.

00:51:46.240 --> 00:51:47.920 align:middle line:84%
Let's say fi can
only go down to 1.

00:51:47.920 --> 00:51:49.645 align:middle line:84%
Otherwise, we'll
get a division by 0.

00:51:49.645 --> 00:51:51.910 align:middle line:84%
We have to deal with
infinity especially.

00:51:51.910 --> 00:51:54.250 align:middle line:84%
Probably, the problem isn't
even well defined then.

00:51:54.250 --> 00:51:55.270 align:middle line:90%
How big could this be?

00:51:55.270 --> 00:51:57.049 align:middle line:90%
Well, I know the wi's--

00:51:57.049 --> 00:51:58.632 align:middle line:84%
AUDIENCE: f's are
defined as positive.

00:51:58.632 --> 00:51:59.890 align:middle line:90%
ERIK DEMAINE: Oh, good.

00:51:59.890 --> 00:52:00.498 align:middle line:90%
Thank you.

00:52:00.498 --> 00:52:02.290 align:middle line:84%
So there's also a
positive constraint here.

00:52:02.290 --> 00:52:07.720 align:middle line:84%
Just I failed to preserve
that constraint in my mapping

00:52:07.720 --> 00:52:10.150 align:middle line:84%
from the word problem
into the formal problem.

00:52:10.150 --> 00:52:12.950 align:middle line:90%


00:52:12.950 --> 00:52:14.800 align:middle line:90%
So f is the least 1.

00:52:14.800 --> 00:52:15.490 align:middle line:90%
Good.

00:52:15.490 --> 00:52:17.890 align:middle line:90%
But worst case is when it's 1.

00:52:17.890 --> 00:52:19.730 align:middle line:84%
And when wi-- how
big could it be?

00:52:19.730 --> 00:52:21.340 align:middle line:90%
Well, n squared minus 1.

00:52:21.340 --> 00:52:23.680 align:middle line:84%
So this could be,
basically, n squared

00:52:23.680 --> 00:52:27.415 align:middle line:84%
times n to the 4th divided
by 1, which is n to the 6th.

00:52:27.415 --> 00:52:31.720 align:middle line:84%
So w-- or sorry, u, the
largest key I can have plus 1,

00:52:31.720 --> 00:52:33.550 align:middle line:90%
is n to the 6th.

00:52:33.550 --> 00:52:36.400 align:middle line:84%
But that's OK, because
radix sort can handle

00:52:36.400 --> 00:52:38.780 align:middle line:90%
any fixed polynomial in n.

00:52:38.780 --> 00:52:41.305 align:middle line:84%
So it's going to end up doing
six counting sort passes.

00:52:41.305 --> 00:52:46.960 align:middle line:90%


00:52:46.960 --> 00:52:51.820 align:middle line:90%
OK, that's problem 3.

00:52:51.820 --> 00:52:54.640 align:middle line:90%
Let's move on to problem 4.

00:52:54.640 --> 00:53:18.390 align:middle line:90%


00:53:18.390 --> 00:53:22.260 align:middle line:84%
So problem 4, MIT has
employed Gank Frehry.

00:53:22.260 --> 00:53:22.800 align:middle line:90%
Who's that?

00:53:22.800 --> 00:53:26.610 align:middle line:90%


00:53:26.610 --> 00:53:27.790 align:middle line:90%
Frank Gehry, yeah.

00:53:27.790 --> 00:53:34.970 align:middle line:84%
This is a common encoding
that Jason really likes.

00:53:34.970 --> 00:53:38.820 align:middle line:90%
I've grown to like it.

00:53:38.820 --> 00:53:42.720 align:middle line:84%
This is called spoonerism,
where you replace some part

00:53:42.720 --> 00:53:45.580 align:middle line:90%
of the beginning of your thing.

00:53:45.580 --> 00:53:47.410 align:middle line:90%
OK, that's one joke.

00:53:47.410 --> 00:53:49.357 align:middle line:84%
There's another joke
in this problem.

00:53:49.357 --> 00:53:51.690 align:middle line:84%
Anyway, they're building a
new wing of the Stata Center,

00:53:51.690 --> 00:53:53.280 align:middle line:90%
as one does.

00:53:53.280 --> 00:53:55.510 align:middle line:90%
We have a bunch of cubes.

00:53:55.510 --> 00:53:58.620 align:middle line:84%
If you read long enough, you
realize that's a red herring.

00:53:58.620 --> 00:54:00.810 align:middle line:84%
Cubes do not play a
role in this problem.

00:54:00.810 --> 00:54:03.870 align:middle line:84%
In the end, what
we have is a bunch

00:54:03.870 --> 00:54:10.197 align:middle line:84%
of integers, which happen to be
the side length of the cubes.

00:54:10.197 --> 00:54:12.030 align:middle line:84%
But we just care about
the side lengths, not

00:54:12.030 --> 00:54:14.310 align:middle line:90%
their volume or anything--

00:54:14.310 --> 00:54:21.640 align:middle line:90%
s n minus 1.

00:54:21.640 --> 00:54:32.015 align:middle line:84%
And we want two numbers
in s summing to h.

00:54:32.015 --> 00:54:34.440 align:middle line:84%
AUDIENCE: This is
dumb, but how can cubes

00:54:34.440 --> 00:54:36.553 align:middle line:90%
have more than six sides?

00:54:36.553 --> 00:54:38.220 align:middle line:84%
ERIK DEMAINE: This
is a side length, not

00:54:38.220 --> 00:54:39.610 align:middle line:90%
the number of sides.

00:54:39.610 --> 00:54:40.470 align:middle line:90%
So a cube--

00:54:40.470 --> 00:54:43.518 align:middle line:90%
AUDIENCE: Oh, OK.

00:54:43.518 --> 00:54:44.310 align:middle line:90%
ERIK DEMAINE: Cool.

00:54:44.310 --> 00:54:46.470 align:middle line:84%
I didn't know we'd be
doing 3D geometry today.

00:54:46.470 --> 00:54:48.090 align:middle line:90%
That's si.

00:54:48.090 --> 00:54:49.800 align:middle line:90%
OK, so you got little cubes.

00:54:49.800 --> 00:54:52.020 align:middle line:90%
You've got big cubes.

00:54:52.020 --> 00:54:53.100 align:middle line:90%
This is a small si.

00:54:53.100 --> 00:54:53.910 align:middle line:90%
This is a big si.

00:54:53.910 --> 00:54:54.868 align:middle line:90%
Doesn't matter, though.

00:54:54.868 --> 00:54:56.163 align:middle line:90%
They're just numbers.

00:54:56.163 --> 00:54:57.330 align:middle line:90%
We're not using them at all.

00:54:57.330 --> 00:54:58.650 align:middle line:84%
In the problem,
you're trying to like

00:54:58.650 --> 00:54:59.860 align:middle line:90%
stack one cube on the other.

00:54:59.860 --> 00:55:01.820 align:middle line:84%
But all we really care
about is two numbers

00:55:01.820 --> 00:55:06.930 align:middle line:84%
whose sum, regular old
sum, is exactly h, ideally.

00:55:06.930 --> 00:55:09.250 align:middle line:84%
There's going to be two
versions of this problem.

00:55:09.250 --> 00:55:12.360 align:middle line:84%
And so the first goal
is to solve this exactly

00:55:12.360 --> 00:55:17.550 align:middle line:90%
in linear expected time.

00:55:17.550 --> 00:55:20.100 align:middle line:90%
That's what the problem says.

00:55:20.100 --> 00:55:23.110 align:middle line:90%
So what do we know?

00:55:23.110 --> 00:55:24.523 align:middle line:90%
Well, linear time, that's--

00:55:24.523 --> 00:55:26.940 align:middle line:84%
can't get much faster than
that, because we need that just

00:55:26.940 --> 00:55:28.170 align:middle line:90%
to read the input.

00:55:28.170 --> 00:55:32.220 align:middle line:90%
Expected time-- hashing, right?

00:55:32.220 --> 00:55:34.680 align:middle line:84%
We're told, basically,
we should use hashing.

00:55:34.680 --> 00:55:36.540 align:middle line:84%
Now, if we're really
annoying, maybe we

00:55:36.540 --> 00:55:38.290 align:middle line:84%
throw that in even
when you don't need it.

00:55:38.290 --> 00:55:40.750 align:middle line:90%
But that's pretty rare.

00:55:40.750 --> 00:55:43.728 align:middle line:84%
So when we see expected,
we should, in a problem

00:55:43.728 --> 00:55:45.270 align:middle line:84%
set setting like
this-- in real life,

00:55:45.270 --> 00:55:46.728 align:middle line:84%
you never know what
you should use.

00:55:46.728 --> 00:55:49.110 align:middle line:84%
But in our-- with your
learning in this class,

00:55:49.110 --> 00:55:51.082 align:middle line:84%
we're going to tell
you basically what

00:55:51.082 --> 00:55:52.290 align:middle line:90%
tricks you're allowed to use.

00:55:52.290 --> 00:55:54.040 align:middle line:84%
Here, you're allowed
to use randomization.

00:55:54.040 --> 00:55:55.590 align:middle line:90%
So probably, we need it.

00:55:55.590 --> 00:55:59.760 align:middle line:84%
Indeed, you need it
to achieve this bound.

00:55:59.760 --> 00:56:01.650 align:middle line:90%
Cool.

00:56:01.650 --> 00:56:03.210 align:middle line:90%
Hashing.

00:56:03.210 --> 00:56:05.460 align:middle line:84%
Not obvious how to approach
this problem with hashing.

00:56:05.460 --> 00:56:08.640 align:middle line:84%
So I'm going to
give you the way I--

00:56:08.640 --> 00:56:10.800 align:middle line:84%
it's hard for me to not
know this algorithm.

00:56:10.800 --> 00:56:14.400 align:middle line:84%
But to me, the first thing
you should think about

00:56:14.400 --> 00:56:17.760 align:middle line:84%
is if I have linear
time and n things,

00:56:17.760 --> 00:56:22.800 align:middle line:84%
and I'm going to use hashing,
the obvious thing to do

00:56:22.800 --> 00:56:25.590 align:middle line:84%
is to take those n things
and put them in a hash table.

00:56:25.590 --> 00:56:26.400 align:middle line:90%
Build.

00:56:26.400 --> 00:56:28.540 align:middle line:90%
Why not?

00:56:28.540 --> 00:56:38.400 align:middle line:84%
So let's just build a hash
table on all the keys in s.

00:56:38.400 --> 00:56:39.540 align:middle line:90%
That's idea one.

00:56:39.540 --> 00:56:45.510 align:middle line:90%


00:56:45.510 --> 00:56:46.980 align:middle line:84%
Seems like the
first thing to try.

00:56:46.980 --> 00:56:49.440 align:middle line:90%
So what does that let me do?

00:56:49.440 --> 00:56:50.640 align:middle line:90%
It lets me--

00:56:50.640 --> 00:56:52.950 align:middle line:84%
I just erased the
interface for hash tables.

00:56:52.950 --> 00:56:55.170 align:middle line:84%
But I can build a
sequence out of it.

00:56:55.170 --> 00:56:57.630 align:middle line:84%
But normally, it gives
me a set interface.

00:56:57.630 --> 00:56:59.880 align:middle line:84%
So I can call find
now in constant time.

00:56:59.880 --> 00:57:03.330 align:middle line:84%
It lets me, given the
number, determine immediately

00:57:03.330 --> 00:57:06.050 align:middle line:90%
whether that number is in s.

00:57:06.050 --> 00:57:07.800 align:middle line:84%
Well, that sounds
interesting, because I'm

00:57:07.800 --> 00:57:09.990 align:middle line:90%
looking for two numbers in s.

00:57:09.990 --> 00:57:11.740 align:middle line:90%
So it lets me find one of them.

00:57:11.740 --> 00:57:13.710 align:middle line:90%
So I call it twice?

00:57:13.710 --> 00:57:14.880 align:middle line:90%
No.

00:57:14.880 --> 00:57:17.342 align:middle line:84%
Calling it twice and only
spending constant time

00:57:17.342 --> 00:57:19.050 align:middle line:84%
on this beautiful data
structure will not

00:57:19.050 --> 00:57:20.220 align:middle line:90%
give you anything useful.

00:57:20.220 --> 00:57:23.310 align:middle line:90%


00:57:23.310 --> 00:57:25.070 align:middle line:90%
But we have linear time, right?

00:57:25.070 --> 00:57:26.940 align:middle line:84%
So in addition to
building a table,

00:57:26.940 --> 00:57:29.730 align:middle line:84%
we could call find on
that table a linear number

00:57:29.730 --> 00:57:32.610 align:middle line:84%
of times, because each find
only takes constant expected

00:57:32.610 --> 00:57:33.910 align:middle line:90%
amortized time.

00:57:33.910 --> 00:57:37.410 align:middle line:84%
So if I do n of them, that
will take linear expected time.

00:57:37.410 --> 00:57:40.850 align:middle line:84%
The amortization disappears,
because I'm using it n times.

00:57:40.850 --> 00:57:41.725 align:middle line:90%
AUDIENCE: [INAUDIBLE]

00:57:41.725 --> 00:57:42.725 align:middle line:90%
ERIK DEMAINE: Oh, right.

00:57:42.725 --> 00:57:44.020 align:middle line:90%
Find never has amortization.

00:57:44.020 --> 00:57:46.740 align:middle line:84%
So it doesn't disappear,
because it was never there.

00:57:46.740 --> 00:57:47.610 align:middle line:90%
Never mind.

00:57:47.610 --> 00:57:52.530 align:middle line:84%
I can afford n calls,
or 5n calls, to find,

00:57:52.530 --> 00:57:55.290 align:middle line:84%
because each one costs
constant expected.

00:57:55.290 --> 00:57:57.250 align:middle line:84%
And the total for that
will be linear time.

00:57:57.250 --> 00:58:04.966 align:middle line:84%
So the next idea is let's
just somehow call find

00:58:04.966 --> 00:58:12.280 align:middle line:90%
a linear number of times, OK?

00:58:12.280 --> 00:58:16.440 align:middle line:84%
So I want to find two numbers
summing to a given value, h.

00:58:16.440 --> 00:58:19.540 align:middle line:84%
That wasn't maybe
clear, but h is given.

00:58:19.540 --> 00:58:20.440 align:middle line:90%
AUDIENCE: Sorry.

00:58:20.440 --> 00:58:22.720 align:middle line:84%
How long does it take
to build the hash table?

00:58:22.720 --> 00:58:24.130 align:middle line:84%
ERIK DEMAINE: How long does
it take to build a hash table?

00:58:24.130 --> 00:58:26.422 align:middle line:84%
It was previously on this
board-- linear expected time.

00:58:26.422 --> 00:58:29.360 align:middle line:90%


00:58:29.360 --> 00:58:32.421 align:middle line:90%
See previous lecture.

00:58:32.421 --> 00:58:35.220 align:middle line:90%
No, two years ago.

00:58:35.220 --> 00:58:35.860 align:middle line:90%
OK.

00:58:35.860 --> 00:58:37.410 align:middle line:84%
Well, if we're going to do
this a linear number of times,

00:58:37.410 --> 00:58:39.310 align:middle line:84%
I guess we should
have a for loop.

00:58:39.310 --> 00:58:41.145 align:middle line:84%
Let's do a for loop
over the numbers.

00:58:41.145 --> 00:58:44.370 align:middle line:90%
That's the next idea.

00:58:44.370 --> 00:58:48.247 align:middle line:90%
Loop over s.

00:58:48.247 --> 00:58:49.830 align:middle line:84%
And at this point,
we're done, almost.

00:58:49.830 --> 00:58:52.560 align:middle line:90%


00:58:52.560 --> 00:58:55.330 align:middle line:90%
I want space.

00:58:55.330 --> 00:58:57.000 align:middle line:84%
So I want to loop
over the numbers.

00:58:57.000 --> 00:58:58.860 align:middle line:84%
And each one, I
want to do a find.

00:58:58.860 --> 00:59:00.900 align:middle line:84%
That's kind of all
I have time to do.

00:59:00.900 --> 00:59:04.900 align:middle line:84%
So seems like a
natural thing to try.

00:59:04.900 --> 00:59:06.670 align:middle line:90%
This is by no means easy.

00:59:06.670 --> 00:59:07.890 align:middle line:90%
Don't get me wrong.

00:59:07.890 --> 00:59:09.570 align:middle line:90%
Having these ideas is--

00:59:09.570 --> 00:59:12.150 align:middle line:84%
while I'm explaining them
as the obvious ideas,

00:59:12.150 --> 00:59:13.600 align:middle line:90%
they're not obvious.

00:59:13.600 --> 00:59:17.040 align:middle line:84%
But they are easy,
at least, just not

00:59:17.040 --> 00:59:19.300 align:middle line:84%
obvious to come up
with the easy ideas.

00:59:19.300 --> 00:59:22.590 align:middle line:84%
So let's loop over
s, somehow call find,

00:59:22.590 --> 00:59:23.670 align:middle line:90%
using our hash table.

00:59:23.670 --> 00:59:25.860 align:middle line:84%
So the order is actually, we're
going to build the hash table,

00:59:25.860 --> 00:59:26.500 align:middle line:90%
then loop.

00:59:26.500 --> 00:59:28.583 align:middle line:84%
And inside the loop, we're
going to call find once

00:59:28.583 --> 00:59:31.000 align:middle line:90%
per loop iteration.

00:59:31.000 --> 00:59:32.020 align:middle line:90%
So let's do it.

00:59:32.020 --> 00:59:37.410 align:middle line:90%
Let's say, for si in S--

00:59:37.410 --> 00:59:40.320 align:middle line:90%


00:59:40.320 --> 00:59:42.210 align:middle line:90%
so I want to find two numbers.

00:59:42.210 --> 00:59:46.050 align:middle line:84%
Here, I have exhaustively
looped over one number.

00:59:46.050 --> 00:59:47.850 align:middle line:84%
I just need to find
the second number that

00:59:47.850 --> 00:59:49.600 align:middle line:90%
can possibly add up, right?

00:59:49.600 --> 00:59:57.390 align:middle line:84%
I want to find whether
there's an sj in S such

00:59:57.390 --> 01:00:05.090 align:middle line:90%
that si plus sj equals h.

01:00:05.090 --> 01:00:08.030 align:middle line:90%


01:00:08.030 --> 01:00:09.530 align:middle line:90%
Can I do that query with find?

01:00:09.530 --> 01:00:12.290 align:middle line:90%


01:00:12.290 --> 01:00:12.790 align:middle line:90%
How?

01:00:12.790 --> 01:00:16.350 align:middle line:90%


01:00:16.350 --> 01:00:17.790 align:middle line:90%
So what does find do?

01:00:17.790 --> 01:00:22.590 align:middle line:84%
Find says, if I give you a key,
it will tell me whether-- like,

01:00:22.590 --> 01:00:25.800 align:middle line:84%
if I knew what sj
was, it would tell me

01:00:25.800 --> 01:00:29.346 align:middle line:90%
whether it's in S. Yeah?

01:00:29.346 --> 01:00:31.776 align:middle line:84%
AUDIENCE: Can't you
just subtract h from si

01:00:31.776 --> 01:00:33.450 align:middle line:90%
and then see if [INAUDIBLE]?

01:00:33.450 --> 01:00:38.860 align:middle line:84%
ERIK DEMAINE: Subtract h from
si and see whether that exists.

01:00:38.860 --> 01:00:39.720 align:middle line:90%
Did get it right?

01:00:39.720 --> 01:00:40.890 align:middle line:90%
AUDIENCE: h minus si.

01:00:40.890 --> 01:00:42.092 align:middle line:90%
ERIK DEMAINE: h minus si.

01:00:42.092 --> 01:00:43.582 align:middle line:90%
I always get it wrong.

01:00:43.582 --> 01:00:46.500 align:middle line:90%


01:00:46.500 --> 01:00:48.330 align:middle line:84%
Don't feel bad that
you also got it wrong.

01:00:48.330 --> 01:00:51.040 align:middle line:84%
It makes me feel better,
because I always get it wrong.

01:00:51.040 --> 01:00:52.650 align:middle line:90%
So the claim is this.

01:00:52.650 --> 01:00:53.460 align:middle line:90%
Why?

01:00:53.460 --> 01:00:57.570 align:middle line:84%
Because what we
want to do is find--

01:00:57.570 --> 01:00:58.890 align:middle line:90%
well, OK.

01:00:58.890 --> 01:01:01.040 align:middle line:84%
Let's see what it
says over here.

01:01:01.040 --> 01:01:05.100 align:middle line:84%
So if we do h minus
si equals sj--

01:01:05.100 --> 01:01:07.740 align:middle line:84%
so these are
equivalent statements,

01:01:07.740 --> 01:01:10.320 align:middle line:90%
just by moving the si over.

01:01:10.320 --> 01:01:12.460 align:middle line:90%
And this is a query we can do.

01:01:12.460 --> 01:01:15.330 align:middle line:84%
So let's remember, these
are things we know.

01:01:15.330 --> 01:01:19.830 align:middle line:90%


01:01:19.830 --> 01:01:21.870 align:middle line:84%
And s.j is something
we don't know.

01:01:21.870 --> 01:01:24.140 align:middle line:84%
All that we know
is that it's an s.

01:01:24.140 --> 01:01:25.650 align:middle line:90%
OK, so we know these two things.

01:01:25.650 --> 01:01:27.970 align:middle line:84%
So if we bring them
over to the same side,

01:01:27.970 --> 01:01:30.220 align:middle line:84%
we're searching for
an unknown thing,

01:01:30.220 --> 01:01:33.030 align:middle line:84%
which is equal to exactly this
thing that we can compute.

01:01:33.030 --> 01:01:35.190 align:middle line:90%
So we just compute h minus si.

01:01:35.190 --> 01:01:35.910 align:middle line:90%
We call find.

01:01:35.910 --> 01:01:40.230 align:middle line:84%
That will tell us whether
there is an sj equal to this.

01:01:40.230 --> 01:01:43.590 align:middle line:90%
OK, so this is like a comment.

01:01:43.590 --> 01:01:45.990 align:middle line:90%
And this is what we actually do.

01:01:45.990 --> 01:01:49.050 align:middle line:84%
And if there is a pair
of numbers summing to h,

01:01:49.050 --> 01:01:50.400 align:middle line:90%
this will find it.

01:01:50.400 --> 01:01:52.090 align:middle line:90%
How much time did it take?

01:01:52.090 --> 01:01:54.690 align:middle line:84%
Well, we're doing n
iterations of this loop.

01:01:54.690 --> 01:01:57.450 align:middle line:84%
Each one, we're calling
a single find operation.

01:01:57.450 --> 01:02:01.760 align:middle line:84%
And find costs
constant expected time.

01:02:01.760 --> 01:02:05.700 align:middle line:84%
And so the total is
linear expected time.

01:02:05.700 --> 01:02:07.050 align:middle line:90%
Great.

01:02:07.050 --> 01:02:08.136 align:middle line:90%
Part A done.

01:02:08.136 --> 01:02:19.560 align:middle line:90%


01:02:19.560 --> 01:02:24.330 align:middle line:84%
Then they throw part b
at us, make it harder.

01:02:24.330 --> 01:02:25.950 align:middle line:90%
Those pesky instructors.

01:02:25.950 --> 01:02:33.680 align:middle line:90%


01:02:33.680 --> 01:02:37.010 align:middle line:90%
So we read part b.

01:02:37.010 --> 01:02:41.240 align:middle line:84%
Part b says two things
to make it harder.

01:02:41.240 --> 01:02:45.200 align:middle line:84%
So first of all, we want
linear worst-case time.

01:02:45.200 --> 01:02:50.290 align:middle line:90%


01:02:50.290 --> 01:02:54.360 align:middle line:84%
And furthermore-- so we
can't use hashing anymore.

01:02:54.360 --> 01:02:57.270 align:middle line:84%
Furthermore-- so
here, we just needed

01:02:57.270 --> 01:02:59.460 align:middle line:84%
to solve the exact problem
to find whether the two

01:02:59.460 --> 01:03:01.470 align:middle line:90%
numbers sum exactly to h.

01:03:01.470 --> 01:03:04.350 align:middle line:84%
Now we would like to find the
best solution smaller than

01:03:04.350 --> 01:03:05.940 align:middle line:90%
or equal to h.

01:03:05.940 --> 01:03:17.730 align:middle line:84%
So find biggest
pairwise sum that's

01:03:17.730 --> 01:03:22.890 align:middle line:84%
less than or equal to h if
there's no perfect pair.

01:03:22.890 --> 01:03:28.620 align:middle line:84%
But we're given a little bit
of extra information, which

01:03:28.620 --> 01:03:37.122 align:middle line:84%
is, we can assume h
equals 600 n to the 6th.

01:03:37.122 --> 01:03:40.620 align:middle line:90%
That's a weird polynomial.

01:03:40.620 --> 01:03:43.380 align:middle line:84%
Took me a while to even notice
that that was a joke in here--

01:03:43.380 --> 01:03:46.950 align:middle line:90%
6006, hiding in a polynomial.

01:03:46.950 --> 01:03:49.470 align:middle line:90%
All right, so polynomial.

01:03:49.470 --> 01:03:51.060 align:middle line:90%
Hm.

01:03:51.060 --> 01:03:52.680 align:middle line:84%
That should make you
think radix sort.

01:03:52.680 --> 01:03:54.160 align:middle line:90%
It is radix sort week.

01:03:54.160 --> 01:03:56.160 align:middle line:84%
So that is a natural
thing to try.

01:03:56.160 --> 01:03:58.530 align:middle line:84%
But in general, even
later in the semester,

01:03:58.530 --> 01:04:02.580 align:middle line:84%
when you see a nice
polynomial with a fixed

01:04:02.580 --> 01:04:04.178 align:middle line:84%
constant like this,
and it's somehow

01:04:04.178 --> 01:04:05.970 align:middle line:84%
related to the integers
we're dealing with,

01:04:05.970 --> 01:04:07.137 align:middle line:90%
you should think radix sort.

01:04:07.137 --> 01:04:09.730 align:middle line:84%
Especially because now, we
want constant worst-case time,

01:04:09.730 --> 01:04:11.820 align:middle line:84%
radix sort seems like
a good thing to do.

01:04:11.820 --> 01:04:13.380 align:middle line:84%
Don't know what
to do with it yet.

01:04:13.380 --> 01:04:15.810 align:middle line:84%
In fact, I can't even
apply radix sort.

01:04:15.810 --> 01:04:19.170 align:middle line:90%
But idea one is radix sort.

01:04:19.170 --> 01:04:21.000 align:middle line:84%
Just because I see
that polynomial,

01:04:21.000 --> 01:04:24.600 align:middle line:90%
I think maybe I should try it.

01:04:24.600 --> 01:04:27.690 align:middle line:84%
Now, there's a problem here,
because we're given some

01:04:27.690 --> 01:04:31.080 align:middle line:90%
numbers, some integers, si's.

01:04:31.080 --> 01:04:32.010 align:middle line:90%
We're also given h.

01:04:32.010 --> 01:04:34.510 align:middle line:84%
We're told now that is a
nice, small polynomial.

01:04:34.510 --> 01:04:37.710 align:middle line:84%
But we have no idea how
big these numbers are.

01:04:37.710 --> 01:04:39.540 align:middle line:84%
So the problem with
this idea is that--

01:04:39.540 --> 01:04:43.180 align:middle line:90%


01:04:43.180 --> 01:04:46.260 align:middle line:90%
but si could be bigger than h.

01:04:46.260 --> 01:04:48.420 align:middle line:84%
We have no idea how
big the si's are.

01:04:48.420 --> 01:04:51.140 align:middle line:90%


01:04:51.140 --> 01:04:53.510 align:middle line:84%
What can I say
about si's that are

01:04:53.510 --> 01:04:57.400 align:middle line:90%
bigger than h for this problem?

01:04:57.400 --> 01:05:00.100 align:middle line:90%


01:05:00.100 --> 01:05:02.360 align:middle line:90%
Summing to h.

01:05:02.360 --> 01:05:02.860 align:middle line:90%
Oh.

01:05:02.860 --> 01:05:05.193 align:middle line:84%
I didn't say it, but all these
numbers are non-negative.

01:05:05.193 --> 01:05:06.490 align:middle line:90%
That's important.

01:05:06.490 --> 01:05:09.160 align:middle line:90%
That looks like [INAUDIBLE].

01:05:09.160 --> 01:05:11.581 align:middle line:90%
Greater than or equal to 0.

01:05:11.581 --> 01:05:16.580 align:middle line:90%


01:05:16.580 --> 01:05:17.080 align:middle line:90%
Yeah?

01:05:17.080 --> 01:05:18.640 align:middle line:84%
AUDIENCE: [INAUDIBLE]
solution [INAUDIBLE]..

01:05:18.640 --> 01:05:19.420 align:middle line:90%
ERIK DEMAINE: Right.

01:05:19.420 --> 01:05:21.587 align:middle line:84%
If I'm finding a sum that's
less than or equal to h,

01:05:21.587 --> 01:05:22.810 align:middle line:90%
they're non-negative.

01:05:22.810 --> 01:05:28.540 align:middle line:84%
And any number that's greater
than h, I can just throw away.

01:05:28.540 --> 01:05:29.920 align:middle line:90%
They'll never be in a solution.

01:05:29.920 --> 01:05:32.670 align:middle line:84%
So they already-- a sum of
one number is bigger than h.

01:05:32.670 --> 01:05:35.175 align:middle line:84%
So two is only going to get
bigger if they're non-negative.

01:05:35.175 --> 01:05:38.090 align:middle line:90%


01:05:38.090 --> 01:05:41.830 align:middle line:84%
So idea number two is let's
just throw out all the big si's,

01:05:41.830 --> 01:05:43.180 align:middle line:90%
anything bigger than h.

01:05:43.180 --> 01:05:46.090 align:middle line:84%
Now, that won't change the
answer, because those can never

01:05:46.090 --> 01:05:47.320 align:middle line:90%
be in a solution.

01:05:47.320 --> 01:05:49.120 align:middle line:84%
And now I have all
the si's having

01:05:49.120 --> 01:05:51.700 align:middle line:84%
the property that they're
less than or equal to h.

01:05:51.700 --> 01:05:56.150 align:middle line:84%
And so they are small,
bounded by a fixed polynomial.

01:05:56.150 --> 01:05:57.600 align:middle line:90%
And now I can apply radix sort.

01:05:57.600 --> 01:06:01.370 align:middle line:84%
So after this idea, I
can apply this idea.

01:06:01.370 --> 01:06:02.830 align:middle line:84%
OK, this gives you
a flavor of how

01:06:02.830 --> 01:06:04.720 align:middle line:90%
I like to think about problems.

01:06:04.720 --> 01:06:06.820 align:middle line:90%
I see clues, like a polynomial.

01:06:06.820 --> 01:06:08.860 align:middle line:90%
I think radix sort doesn't work.

01:06:08.860 --> 01:06:12.655 align:middle line:84%
But with some more ideas,
I can get it to work.

01:06:12.655 --> 01:06:14.370 align:middle line:90%
OK.

01:06:14.370 --> 01:06:16.890 align:middle line:84%
What goes with the--
so now I've sorted si.

01:06:16.890 --> 01:06:18.380 align:middle line:90%
OK, great.

01:06:18.380 --> 01:06:19.550 align:middle line:90%
S is sorted.

01:06:19.550 --> 01:06:23.650 align:middle line:90%


01:06:23.650 --> 01:06:27.250 align:middle line:84%
I guess we can try to
do the same algorithm,

01:06:27.250 --> 01:06:29.540 align:middle line:84%
except I don't have
a hash table anymore.

01:06:29.540 --> 01:06:34.820 align:middle line:84%
So let's just try doing a
for loop over the S. Why not?

01:06:34.820 --> 01:06:40.270 align:middle line:84%
So let's do for si in
S. But now it's sorted.

01:06:40.270 --> 01:06:42.920 align:middle line:84%
So presumably, I should
exploit the sorted order.

01:06:42.920 --> 01:06:45.860 align:middle line:90%
So let's do them in order.

01:06:45.860 --> 01:06:49.870 align:middle line:84%
So i equals 0, 1,
up to n minus 1.

01:06:49.870 --> 01:06:52.030 align:middle line:84%
Let's say that s0
is the smallest.

01:06:52.030 --> 01:06:53.770 align:middle line:90%
s1 is the next smallest.

01:06:53.770 --> 01:06:56.260 align:middle line:90%
sn minus 1 is the biggest.

01:06:56.260 --> 01:06:58.120 align:middle line:90%
So I want to do something with--

01:06:58.120 --> 01:06:59.890 align:middle line:90%
so I have si.

01:06:59.890 --> 01:07:05.200 align:middle line:84%
And I want to figure out
whether h minus si is in there.

01:07:05.200 --> 01:07:08.680 align:middle line:90%


01:07:08.680 --> 01:07:12.040 align:middle line:90%
Hard to do that better than--

01:07:12.040 --> 01:07:15.730 align:middle line:84%
actually, I could do
this with binary search.

01:07:15.730 --> 01:07:18.730 align:middle line:90%
I'm looking for this value.

01:07:18.730 --> 01:07:20.260 align:middle line:90%
And I have a sorted array now.

01:07:20.260 --> 01:07:22.960 align:middle line:84%
So I could binary
search for h minus si.

01:07:22.960 --> 01:07:26.600 align:middle line:84%
And in log n time, I will find
whether that guy is in there.

01:07:26.600 --> 01:07:27.820 align:middle line:90%
And if not, keep looping.

01:07:27.820 --> 01:07:29.960 align:middle line:84%
I can keep track of the
best thing that I found.

01:07:29.960 --> 01:07:32.430 align:middle line:84%
And so in n log n time, I
can definitely solve this.

01:07:32.430 --> 01:07:35.020 align:middle line:90%
But I'd like to get linear time.

01:07:35.020 --> 01:07:36.070 align:middle line:90%
Do you have a question?

01:07:36.070 --> 01:07:37.270 align:middle line:84%
AUDIENCE: Well,
I'm just wondering,

01:07:37.270 --> 01:07:38.512 align:middle line:90%
how would you [INAUDIBLE]?

01:07:38.512 --> 01:07:40.622 align:middle line:84%
Like, why would you
[INAUDIBLE] whether that

01:07:40.622 --> 01:07:41.728 align:middle line:90%
is in there [INAUDIBLE]?

01:07:41.728 --> 01:07:43.270 align:middle line:84%
ERIK DEMAINE: I'm
not looking for si.

01:07:43.270 --> 01:07:45.910 align:middle line:90%
I'm going to compute h minus si.

01:07:45.910 --> 01:07:48.550 align:middle line:84%
So this is-- maybe I shouldn't
even write this down, but--

01:07:48.550 --> 01:07:52.090 align:middle line:84%
AUDIENCE: She's asking about
the [INAUDIBLE] constraint of,

01:07:52.090 --> 01:07:53.290 align:middle line:90%
we're not looking for h.

01:07:53.290 --> 01:07:55.990 align:middle line:84%
We're looking for
something smaller than h.

01:07:55.990 --> 01:07:57.020 align:middle line:90%
ERIK DEMAINE: This one?

01:07:57.020 --> 01:07:57.520 align:middle line:90%
Or--

01:07:57.520 --> 01:07:58.690 align:middle line:90%
AUDIENCE: Something larger.

01:07:58.690 --> 01:07:59.950 align:middle line:90%
ERIK DEMAINE: Oh, this thing.

01:07:59.950 --> 01:08:01.010 align:middle line:84%
AUDIENCE: A large
thing less than h.

01:08:01.010 --> 01:08:01.843 align:middle line:90%
ERIK DEMAINE: Right.

01:08:01.843 --> 01:08:06.100 align:middle line:84%
So in particular, if there
are two items that sum to h,

01:08:06.100 --> 01:08:08.920 align:middle line:90%
I want to find it.

01:08:08.920 --> 01:08:09.970 align:middle line:90%
So let's start with that.

01:08:09.970 --> 01:08:14.710 align:middle line:84%
So I'm binary searching
for h minus si in S.

01:08:14.710 --> 01:08:16.330 align:middle line:90%
So I could certainly do that.

01:08:16.330 --> 01:08:19.737 align:middle line:90%
And if I find it, great.

01:08:19.737 --> 01:08:21.279 align:middle line:84%
I found a pair that
sum to exactly h.

01:08:21.279 --> 01:08:24.670 align:middle line:84%
If I don't find it, binary
search tells me not only

01:08:24.670 --> 01:08:26.229 align:middle line:84%
that it's not there,
but it tells me

01:08:26.229 --> 01:08:28.850 align:middle line:84%
what the previous
and next value are.

01:08:28.850 --> 01:08:30.520 align:middle line:84%
So even though h
minus si isn't there,

01:08:30.520 --> 01:08:33.430 align:middle line:84%
I can get the next largest thing
and the next smallest thing.

01:08:33.430 --> 01:08:35.319 align:middle line:84%
What I want is the
next smallest thing.

01:08:35.319 --> 01:08:39.970 align:middle line:84%
And that will be the largest
sum I can get using si.

01:08:39.970 --> 01:08:43.499 align:middle line:84%
And so then that's one
candidate for a sum less than

01:08:43.499 --> 01:08:44.498 align:middle line:90%
or equal to h.

01:08:44.498 --> 01:08:45.790 align:middle line:90%
I want to find the largest one.

01:08:45.790 --> 01:08:46.899 align:middle line:90%
So I do a for loop.

01:08:46.899 --> 01:08:48.010 align:middle line:90%
I always keep track of--

01:08:48.010 --> 01:08:49.930 align:middle line:84%
I take a list of all
the candidates I got.

01:08:49.930 --> 01:08:53.529 align:middle line:84%
Each time I do an iteration of
this loop, I get one candidate.

01:08:53.529 --> 01:08:56.229 align:middle line:90%
Then I take the largest one.

01:08:56.229 --> 01:08:59.593 align:middle line:90%
OK, so return largest candidate.

01:08:59.593 --> 01:09:06.859 align:middle line:90%


01:09:06.859 --> 01:09:12.910 align:middle line:84%
So this gives me a candidate,
just the previous item.

01:09:12.910 --> 01:09:15.700 align:middle line:84%
This is what we called find
previous, or find prev,

01:09:15.700 --> 01:09:18.220 align:middle line:90%
probably, in our set interface.

01:09:18.220 --> 01:09:21.350 align:middle line:84%
And if you have a sorted set,
you can do that in log n time.

01:09:21.350 --> 01:09:27.382 align:middle line:84%
So this is an n log n solution,
because we do n iterations

01:09:27.382 --> 01:09:28.090 align:middle line:90%
through the loop.

01:09:28.090 --> 01:09:29.920 align:middle line:90%
Each binary search takes log n.

01:09:29.920 --> 01:09:32.510 align:middle line:90%
I want to get linear.

01:09:32.510 --> 01:09:35.455 align:middle line:90%
This is not obvious.

01:09:35.455 --> 01:09:40.689 align:middle line:90%


01:09:40.689 --> 01:09:43.600 align:middle line:84%
The best intuition I can
think of for this next idea

01:09:43.600 --> 01:09:49.750 align:middle line:84%
is, well, I start with the
very smallest item in S.

01:09:49.750 --> 01:09:53.029 align:middle line:84%
And I want to sum up to
something that's kind of big,

01:09:53.029 --> 01:09:53.529 align:middle line:90%
right?

01:09:53.529 --> 01:09:56.920 align:middle line:84%
I threw away all the
items bigger than h.

01:09:56.920 --> 01:10:00.730 align:middle line:84%
If s0 is like tiny,
like close to 0,

01:10:00.730 --> 01:10:02.680 align:middle line:84%
because it's the smallest
one, then maybe I

01:10:02.680 --> 01:10:05.380 align:middle line:84%
should look at the
end of the array,

01:10:05.380 --> 01:10:07.150 align:middle line:84%
because I want to
compare, or I want

01:10:07.150 --> 01:10:08.670 align:middle line:84%
to add the smallest
thing probably

01:10:08.670 --> 01:10:09.820 align:middle line:90%
with the biggest thing.

01:10:09.820 --> 01:10:12.940 align:middle line:84%
That's as close
as I can imagine.

01:10:12.940 --> 01:10:20.530 align:middle line:84%
So then-- so here's my sorted S.
It's the smallest item, biggest

01:10:20.530 --> 01:10:21.320 align:middle line:90%
item.

01:10:21.320 --> 01:10:25.150 align:middle line:84%
So I'm going to loop over
these items one by one.

01:10:25.150 --> 01:10:27.850 align:middle line:84%
So let's start by comparing the
first one with the last one.

01:10:27.850 --> 01:10:31.690 align:middle line:90%


01:10:31.690 --> 01:10:34.630 align:middle line:90%
The two-finger algorithm, OK?

01:10:34.630 --> 01:10:41.950 align:middle line:90%


01:10:41.950 --> 01:10:43.210 align:middle line:90%
This is the big idea.

01:10:43.210 --> 01:10:45.400 align:middle line:84%
You're doing it all
the time in this class.

01:10:45.400 --> 01:10:46.150 align:middle line:90%
It's super useful.

01:10:46.150 --> 01:10:48.880 align:middle line:84%
We saw it in merge sorts, for
example, and merging two lists.

01:10:48.880 --> 01:10:51.190 align:middle line:84%
We have fingers in two
lists that advance.

01:10:51.190 --> 01:10:54.582 align:middle line:84%
And because they only advance,
it takes linear total time.

01:10:54.582 --> 01:10:57.040 align:middle line:84%
So we're going to do this kind
of folded in backwards here.

01:10:57.040 --> 01:10:58.550 align:middle line:90%
We're going to start here.

01:10:58.550 --> 01:11:00.700 align:middle line:84%
This seems like a good
candidate to start with.

01:11:00.700 --> 01:11:03.400 align:middle line:84%
Now, what else
could this add with?

01:11:03.400 --> 01:11:05.650 align:middle line:90%
Well, maybe smaller items.

01:11:05.650 --> 01:11:07.930 align:middle line:84%
And maybe I have to go
all the way through here.

01:11:07.930 --> 01:11:10.345 align:middle line:84%
And then I've got to
advance my left finger.

01:11:10.345 --> 01:11:11.080 align:middle line:90%
Yeah, OK.

01:11:11.080 --> 01:11:15.020 align:middle line:90%
So here's the idea.

01:11:15.020 --> 01:11:19.240 align:middle line:90%
So let's look at--

01:11:19.240 --> 01:11:22.650 align:middle line:84%
so I'm going to call this
finger i and this finger j.

01:11:22.650 --> 01:11:25.070 align:middle line:90%
So we want to sum two things.

01:11:25.070 --> 01:11:27.040 align:middle line:84%
So I guess one other
inspiration here is,

01:11:27.040 --> 01:11:28.390 align:middle line:90%
we want to add two things up.

01:11:28.390 --> 01:11:31.170 align:middle line:84%
And we have one algorithm
that has the word "two" in it.

01:11:31.170 --> 01:11:33.080 align:middle line:84%
And it's the
two-finger algorithm.

01:11:33.080 --> 01:11:34.978 align:middle line:90%
So let's try that.

01:11:34.978 --> 01:11:36.520 align:middle line:84%
So we're going to
start at i equals 0

01:11:36.520 --> 01:11:38.050 align:middle line:90%
and j equals n minus 1.

01:11:38.050 --> 01:11:44.770 align:middle line:84%
We're going to look at si plus
sj and see, how good is it?

01:11:44.770 --> 01:11:46.900 align:middle line:90%
How close to summing to h is it?

01:11:46.900 --> 01:11:51.400 align:middle line:84%
Well, in particular, it's
either less than or equal to h

01:11:51.400 --> 01:11:52.330 align:middle line:90%
or bigger than h.

01:11:52.330 --> 01:11:57.940 align:middle line:90%


01:11:57.940 --> 01:11:59.980 align:middle line:90%
If it's bigger than h--

01:11:59.980 --> 01:12:01.300 align:middle line:90%
so this sum is too big.

01:12:01.300 --> 01:12:03.520 align:middle line:84%
I can't even use
it as a candidate.

01:12:03.520 --> 01:12:06.640 align:middle line:84%
Well, that means I really
don't need this guy, right?

01:12:06.640 --> 01:12:08.020 align:middle line:90%
It's too big overall.

01:12:08.020 --> 01:12:10.450 align:middle line:84%
I'm adding the smallest
item to this item.

01:12:10.450 --> 01:12:11.362 align:middle line:90%
And it's too big.

01:12:11.362 --> 01:12:12.820 align:middle line:84%
Well, then I should
go to the left.

01:12:12.820 --> 01:12:14.960 align:middle line:84%
I should move my right
finger to the left.

01:12:14.960 --> 01:12:19.750 align:middle line:90%
So in this case, we decrement j.

01:12:19.750 --> 01:12:22.520 align:middle line:84%
Move the right
finger to the left.

01:12:22.520 --> 01:12:26.760 align:middle line:84%
So I'm guessing, in this
case, I increment i.

01:12:26.760 --> 01:12:28.660 align:middle line:90%
Why?

01:12:28.660 --> 01:12:32.395 align:middle line:84%
If I add these two items
up, and this is too small,

01:12:32.395 --> 01:12:36.370 align:middle line:84%
it's smaller than h, then this
item was probably too small.

01:12:36.370 --> 01:12:38.215 align:middle line:84%
It might actually--
it's an OK solution.

01:12:38.215 --> 01:12:39.423 align:middle line:90%
It's less than or equal to h.

01:12:39.423 --> 01:12:41.965 align:middle line:84%
So I should keep
it as a candidate.

01:12:41.965 --> 01:12:47.800 align:middle line:90%
Let's say add candidate.

01:12:47.800 --> 01:12:51.220 align:middle line:84%
So I'm just going to keep a
list of candidates that I see.

01:12:51.220 --> 01:12:52.900 align:middle line:90%
So this is a possible solution.

01:12:52.900 --> 01:12:54.430 align:middle line:90%
It might not be the best one.

01:12:54.430 --> 01:12:55.810 align:middle line:90%
But it's one to add to my list.

01:12:55.810 --> 01:13:00.400 align:middle line:84%
And then I'm going to increase i
and now work on this sub-array,

01:13:00.400 --> 01:13:02.510 align:middle line:84%
because that will be
a little bit bigger.

01:13:02.510 --> 01:13:04.160 align:middle line:84%
I can't go this way
to make it bigger,

01:13:04.160 --> 01:13:05.860 align:middle line:90%
because I'm at the last item.

01:13:05.860 --> 01:13:07.690 align:middle line:84%
And it's not obvious
that this works.

01:13:07.690 --> 01:13:15.920 align:middle line:84%
I think there's a nice invariant
that will help somewhere.

01:13:15.920 --> 01:13:17.691 align:middle line:90%
Where'd I put my piece of paper?

01:13:17.691 --> 01:13:22.430 align:middle line:90%


01:13:22.430 --> 01:13:22.930 align:middle line:90%
Yeah.

01:13:22.930 --> 01:13:26.325 align:middle line:90%


01:13:26.325 --> 01:13:28.750 align:middle line:90%
So here's an invariant.

01:13:28.750 --> 01:13:37.076 align:middle line:90%


01:13:37.076 --> 01:13:38.010 align:middle line:90%
Oh, yes.

01:13:38.010 --> 01:14:00.672 align:middle line:90%


01:14:00.672 --> 01:14:02.380 align:middle line:84%
It's really clear this
is the right thing

01:14:02.380 --> 01:14:03.460 align:middle line:90%
to do in the first step.

01:14:03.460 --> 01:14:06.340 align:middle line:84%
And the tricky part is to argue
that it works in all steps,

01:14:06.340 --> 01:14:09.243 align:middle line:84%
because when I really have the
smallest item and the largest

01:14:09.243 --> 01:14:11.535 align:middle line:84%
item, it's clear that I should
advance one or the other

01:14:11.535 --> 01:14:13.060 align:middle line:90%
if I'm too small or too big.

01:14:13.060 --> 01:14:15.520 align:middle line:84%
But the way to prove it
in general by induction

01:14:15.520 --> 01:14:17.290 align:middle line:90%
is to show this invariant that--

01:14:17.290 --> 01:14:19.870 align:middle line:84%
so at some point
through this execution,

01:14:19.870 --> 01:14:21.070 align:middle line:90%
i and j are somewhere.

01:14:21.070 --> 01:14:23.830 align:middle line:84%
And I want to say that if I
take any j from the right--

01:14:23.830 --> 01:14:26.860 align:middle line:84%
any j prime to the right of
j and any i prime to the left

01:14:26.860 --> 01:14:30.310 align:middle line:84%
of i, unstrictly, then
all of those pairs,

01:14:30.310 --> 01:14:33.010 align:middle line:84%
all those pairwise sums,
are either too big--

01:14:33.010 --> 01:14:34.750 align:middle line:90%
and that's when we decrease j--

01:14:34.750 --> 01:14:37.450 align:middle line:84%
or they're less than or equal
to the largest candidate

01:14:37.450 --> 01:14:39.490 align:middle line:90%
that we've seen so far.

01:14:39.490 --> 01:14:42.140 align:middle line:84%
That's because we added
these candidates in there.

01:14:42.140 --> 01:14:45.280 align:middle line:84%
So that invariant will
hold by induction,

01:14:45.280 --> 01:14:47.950 align:middle line:84%
because whenever there's a
possible thing that's good,

01:14:47.950 --> 01:14:49.577 align:middle line:90%
I add it to my candidate list.

01:14:49.577 --> 01:14:51.160 align:middle line:84%
And then, at the end
of the algorithm,

01:14:51.160 --> 01:14:54.250 align:middle line:84%
I just loop through my
candidate list, compute the max,

01:14:54.250 --> 01:14:55.090 align:middle line:90%
return that pair.

01:14:55.090 --> 01:14:58.390 align:middle line:90%


01:14:58.390 --> 01:15:01.600 align:middle line:84%
OK, so that is
two-finger algorithm,

01:15:01.600 --> 01:15:04.360 align:middle line:84%
which solves the
non-exact problem

01:15:04.360 --> 01:15:06.070 align:middle line:90%
in linear worst-case time.

01:15:06.070 --> 01:15:06.570 align:middle line:90%
Yeah?

01:15:06.570 --> 01:15:08.170 align:middle line:84%
AUDIENCE: i cannot
equal j, right?

01:15:08.170 --> 01:15:09.040 align:middle line:84%
ERIK DEMAINE: Oh,
i cannot-- right.

01:15:09.040 --> 01:15:10.900 align:middle line:84%
So what are the
termination conditions?

01:15:10.900 --> 01:15:14.740 align:middle line:84%
When i equals j, that's
probably when you want to stop.

01:15:14.740 --> 01:15:15.350 align:middle line:90%
It depends.

01:15:15.350 --> 01:15:19.540 align:middle line:84%
You could say, if i is
greater than j, stop.

01:15:19.540 --> 01:15:21.230 align:middle line:90%
Return max candidate.

01:15:21.230 --> 01:15:24.005 align:middle line:90%


01:15:24.005 --> 01:15:25.880 align:middle line:84%
There are two ways to
interpret this problem.

01:15:25.880 --> 01:15:29.290 align:middle line:84%
One is that the two
values you choose in S

01:15:29.290 --> 01:15:31.840 align:middle line:84%
need to be different
values, or you

01:15:31.840 --> 01:15:35.080 align:middle line:84%
allow them to be the same value,
like they can both be h over 2.

01:15:35.080 --> 01:15:36.730 align:middle line:84%
And either way is
easier to solve.

01:15:36.730 --> 01:15:39.490 align:middle line:84%
If you want to allow
s over 2, then I

01:15:39.490 --> 01:15:40.660 align:middle line:90%
would put greater than here.

01:15:40.660 --> 01:15:44.470 align:middle line:84%
If you don't want
to allow h over 2,

01:15:44.470 --> 01:15:46.990 align:middle line:84%
then I would put greater
than or equal to--

01:15:46.990 --> 01:15:47.590 align:middle line:90%
either way.

01:15:47.590 --> 01:15:49.870 align:middle line:84%
Both of these problems,
you can solve both ways.

01:15:49.870 --> 01:15:54.820 align:middle line:84%
Or both algorithms can
handle both situations.

01:15:54.820 --> 01:15:57.790 align:middle line:90%
OK, one more problem.

01:15:57.790 --> 01:16:00.950 align:middle line:90%


01:16:00.950 --> 01:16:01.640 align:middle line:90%
All right.

01:16:01.640 --> 01:16:04.100 align:middle line:90%
Yeah, I'm all out of time.

01:16:04.100 --> 01:16:06.740 align:middle line:84%
But I'm getting
faster and faster.

01:16:06.740 --> 01:16:08.180 align:middle line:84%
Of course, on the
hardest problem,

01:16:08.180 --> 01:16:09.590 align:middle line:90%
I can do it the fastest.

01:16:09.590 --> 01:16:14.180 align:middle line:90%
All right, so Meff Ja--

01:16:14.180 --> 01:16:16.880 align:middle line:84%
this is a reference to Jeff
Ma of the MIT Blackjack

01:16:16.880 --> 01:16:19.910 align:middle line:84%
Team, who I got to speak here
at LSC a bunch of years ago.

01:16:19.910 --> 01:16:22.880 align:middle line:84%
But he's featured in
the movie 21 and so on--

01:16:22.880 --> 01:16:25.910 align:middle line:90%
fictionalized.

01:16:25.910 --> 01:16:27.860 align:middle line:90%
So I was playing this game.

01:16:27.860 --> 01:16:29.270 align:middle line:90%
It's a great setup.

01:16:29.270 --> 01:16:31.220 align:middle line:84%
You should definitely
read this problem--

01:16:31.220 --> 01:16:35.120 align:middle line:90%
Po- k -er.

01:16:35.120 --> 01:16:38.930 align:middle line:84%
And he has a deck of
cards, where each card has

01:16:38.930 --> 01:16:40.400 align:middle line:90%
a letter of the alphabet on it.

01:16:40.400 --> 01:16:42.510 align:middle line:84%
I guess this is
the right way up.

01:16:42.510 --> 01:16:44.930 align:middle line:84%
So I, of course,
have such a deck.

01:16:44.930 --> 01:16:46.040 align:middle line:90%
Doesn't everyone?

01:16:46.040 --> 01:16:47.000 align:middle line:90%
You can buy these.

01:16:47.000 --> 01:16:49.370 align:middle line:90%
I have several, actually.

01:16:49.370 --> 01:16:50.990 align:middle line:84%
And so we can do a
quick magic trick,

01:16:50.990 --> 01:16:54.272 align:middle line:84%
like pick a card, any
card-- here, pick a card.

01:16:54.272 --> 01:16:57.710 align:middle line:90%
[INAUDIBLE] OK, good choice.

01:16:57.710 --> 01:16:59.960 align:middle line:84%
I can't force, so it
doesn't really matter.

01:16:59.960 --> 01:17:04.160 align:middle line:84%
OK, and so this is
your card, right?

01:17:04.160 --> 01:17:07.680 align:middle line:90%
And your card is an s, right?

01:17:07.680 --> 01:17:09.560 align:middle line:90%
OK, good.

01:17:09.560 --> 01:17:11.180 align:middle line:90%
No, not all the cards are s's.

01:17:11.180 --> 01:17:14.923 align:middle line:90%
[LAUGHTER]

01:17:14.923 --> 01:17:16.340 align:middle line:84%
But he has mirrors
in his glasses.

01:17:16.340 --> 01:17:17.404 align:middle line:90%
No.

01:17:17.404 --> 01:17:20.630 align:middle line:84%
I can reveal later
how that's done.

01:17:20.630 --> 01:17:22.350 align:middle line:90%
OK, so a deck of cards.

01:17:22.350 --> 01:17:25.730 align:middle line:84%
Each card has 26
possible letters on it.

01:17:25.730 --> 01:17:29.090 align:middle line:84%
And there's this
weird dealing process.

01:17:29.090 --> 01:17:30.590 align:middle line:84%
Even just defining
this problem is

01:17:30.590 --> 01:17:31.370 align:middle line:90%
going to take a little while.

01:17:31.370 --> 01:17:32.578 align:middle line:90%
Oh, here's my piece of paper.

01:17:32.578 --> 01:17:35.930 align:middle line:90%


01:17:35.930 --> 01:17:38.000 align:middle line:90%
So we have this dealing process.

01:17:38.000 --> 01:17:40.310 align:middle line:84%
Here's an example that's
in the program, abcdbc.

01:17:40.310 --> 01:17:45.020 align:middle line:90%


01:17:45.020 --> 01:17:47.330 align:middle line:84%
So you know the
order of the cards.

01:17:47.330 --> 01:17:48.350 align:middle line:90%
This is the top card.

01:17:48.350 --> 01:17:49.940 align:middle line:90%
This is the bottom card.

01:17:49.940 --> 01:17:53.450 align:middle line:90%
And now, randomly, you do a cut.

01:17:53.450 --> 01:17:56.910 align:middle line:90%
Cut is this.

01:17:56.910 --> 01:18:00.140 align:middle line:84%
So I take some chunk off the
top, move it to the bottom,

01:18:00.140 --> 01:18:02.030 align:middle line:90%
once, randomly.

01:18:02.030 --> 01:18:06.080 align:middle line:84%
So for example, I
could take this cut.

01:18:06.080 --> 01:18:13.190 align:middle line:84%
And then what I would get
is cdbc for this part that's

01:18:13.190 --> 01:18:18.840 align:middle line:90%
copied here, and ab as the--

01:18:18.840 --> 01:18:23.490 align:middle line:84%
so this is-- so the first
thing we do is cut at i.

01:18:23.490 --> 01:18:24.780 align:middle line:90%
This is position i.

01:18:24.780 --> 01:18:28.860 align:middle line:90%
In this example, i equals 2.

01:18:28.860 --> 01:18:33.610 align:middle line:84%
OK, then we deal
the top k cards.

01:18:33.610 --> 01:18:38.610 align:middle line:84%
So let's say we deal the
top four cards, k equals 4.

01:18:38.610 --> 01:18:42.960 align:middle line:90%
So this is deal k.

01:18:42.960 --> 01:18:45.900 align:middle line:90%
So we get cdbc, in that order.

01:18:45.900 --> 01:18:48.270 align:middle line:84%
But the order doesn't matter,
because the last operation

01:18:48.270 --> 01:18:53.882 align:middle line:84%
we do in the problem is
sort them, which is bccd,

01:18:53.882 --> 01:18:55.590 align:middle line:84%
like you do when you
get a hand of cards.

01:18:55.590 --> 01:18:57.420 align:middle line:90%
You tend to sort them.

01:18:57.420 --> 01:18:58.860 align:middle line:90%
OK, so this is a process.

01:18:58.860 --> 01:19:03.330 align:middle line:84%
Given a deck-- so the
deck here is fixed.

01:19:03.330 --> 01:19:10.200 align:middle line:84%
We call this process, I
think, P of D comma i comma k.

01:19:10.200 --> 01:19:11.320 align:middle line:90%
We're told what D is.

01:19:11.320 --> 01:19:12.720 align:middle line:90%
We're told what k is.

01:19:12.720 --> 01:19:15.210 align:middle line:90%
i is chosen randomly.

01:19:15.210 --> 01:19:18.090 align:middle line:84%
And we'd like to know what
happens with different i's.

01:19:18.090 --> 01:19:21.160 align:middle line:90%


01:19:21.160 --> 01:19:24.265 align:middle line:84%
So if you stare at this problem
enough, it begins to simplify.

01:19:24.265 --> 01:19:26.382 align:middle line:90%
So this is a complicated setup.

01:19:26.382 --> 01:19:28.840 align:middle line:84%
But what's really going on is
we're starting at position i.

01:19:28.840 --> 01:19:32.830 align:middle line:84%
And we're taking the next k
cards from there cyclically.

01:19:32.830 --> 01:19:34.270 align:middle line:84%
So here, we just
took those four.

01:19:34.270 --> 01:19:38.410 align:middle line:84%
If i equaled 3, we would deal
d, then b, then c, then a.

01:19:38.410 --> 01:19:40.290 align:middle line:90%
But then we sort them.

01:19:40.290 --> 01:19:43.240 align:middle line:84%
OK, so we're getting different
substrings of length k,

01:19:43.240 --> 01:19:44.350 align:middle line:90%
cyclically.

01:19:44.350 --> 01:19:46.710 align:middle line:84%
But then we're
sorting those letters.

01:19:46.710 --> 01:19:48.460 align:middle line:84%
Sorting is really
crucial for this problem

01:19:48.460 --> 01:19:50.890 align:middle line:90%
to at all be feasible.

01:19:50.890 --> 01:19:53.780 align:middle line:84%
It took me a while even to
see how to solve this problem.

01:19:53.780 --> 01:19:56.950 align:middle line:84%
But the key is sorting,
that they get sorted,

01:19:56.950 --> 01:19:59.350 align:middle line:90%
because that means--

01:19:59.350 --> 01:20:01.630 align:middle line:84%
because we sort, it
doesn't matter whether you

01:20:01.630 --> 01:20:08.050 align:middle line:90%
have aaba, or baaa, or abaa.

01:20:08.050 --> 01:20:10.490 align:middle line:90%
These are all the same.

01:20:10.490 --> 01:20:12.550 align:middle line:84%
If you take these
cards dealt, you

01:20:12.550 --> 01:20:15.130 align:middle line:84%
sort them to the
same thing, which is

01:20:15.130 --> 01:20:17.650 align:middle line:90%
the one I didn't write, aaab.

01:20:17.650 --> 01:20:20.150 align:middle line:84%
All of these get sorted
to the same thing.

01:20:20.150 --> 01:20:23.970 align:middle line:84%
So we lost some information
when we sort, lost the order.

01:20:23.970 --> 01:20:25.680 align:middle line:84%
The first question
to get you thinking

01:20:25.680 --> 01:20:29.970 align:middle line:84%
in this direction, part a,
says, build a data structure

01:20:29.970 --> 01:20:36.600 align:middle line:84%
given D and k that lets me know,
given two indices, i and j,

01:20:36.600 --> 01:20:39.670 align:middle line:84%
do I end up with
the exact same hand?

01:20:39.670 --> 01:20:43.080 align:middle line:90%
This thing is called a hand.

01:20:43.080 --> 01:20:46.770 align:middle line:90%
And it's exactly this P D, i, k.

01:20:46.770 --> 01:20:50.610 align:middle line:84%
So I want to do P D,
i, k and P, d, j, k.

01:20:50.610 --> 01:20:51.480 align:middle line:90%
And I want to know--

01:20:51.480 --> 01:20:52.260 align:middle line:90%
JK.

01:20:52.260 --> 01:20:54.480 align:middle line:84%
And I want to know whether
those two things are

01:20:54.480 --> 01:20:57.340 align:middle line:90%
equal in constant time.

01:20:57.340 --> 01:20:58.380 align:middle line:90%
That's what this says--

01:20:58.380 --> 01:21:00.240 align:middle line:90%
constant time.

01:21:00.240 --> 01:21:02.835 align:middle line:84%
Doesn't say worst case,
but worst case is possible.

01:21:02.835 --> 01:21:06.577 align:middle line:90%


01:21:06.577 --> 01:21:08.160 align:middle line:84%
And that sounds hard,
because, I mean,

01:21:08.160 --> 01:21:10.560 align:middle line:84%
there's k symbols for one
of them, another k symbols

01:21:10.560 --> 01:21:11.312 align:middle line:90%
for the other guy.

01:21:11.312 --> 01:21:13.020 align:middle line:84%
But we don't have to
compare the symbols.

01:21:13.020 --> 01:21:17.220 align:middle line:84%
We just need to compare the
sorting of those strings.

01:21:17.220 --> 01:21:19.620 align:middle line:90%
And this, we can compress.

01:21:19.620 --> 01:21:21.570 align:middle line:90%
So this is a subtlety.

01:21:21.570 --> 01:21:24.210 align:middle line:84%
But all I really need to know
is that there are three a's

01:21:24.210 --> 01:21:30.260 align:middle line:84%
here, and one b, and zero
c's, and zero d's, and zero

01:21:30.260 --> 01:21:31.980 align:middle line:90%
e's, and so on.

01:21:31.980 --> 01:21:35.310 align:middle line:84%
But because there's only
26 letters in this deck--

01:21:35.310 --> 01:21:38.480 align:middle line:84%
and indeed, in this deck, it
happens upper and lowercase a

01:21:38.480 --> 01:21:39.180 align:middle line:90%
through z.

01:21:39.180 --> 01:21:41.220 align:middle line:90%
But we might have n cards.

01:21:41.220 --> 01:21:43.190 align:middle line:84%
But there are only
26 possible labels.

01:21:43.190 --> 01:21:44.648 align:middle line:84%
So in fact, a lot
of them are going

01:21:44.648 --> 01:21:46.390 align:middle line:90%
to be equal if n is large.

01:21:46.390 --> 01:21:47.940 align:middle line:84%
So this is a good
compression scheme,

01:21:47.940 --> 01:21:52.620 align:middle line:84%
because to represent the things
I get after sorting, I just

01:21:52.620 --> 01:21:54.830 align:middle line:90%
need to give you 26 numbers.

01:21:54.830 --> 01:21:58.050 align:middle line:84%
And for us, 26 is small,
because 26 is a constant.

01:21:58.050 --> 01:22:00.690 align:middle line:84%
Independent of the number of
cards, I just need to say,

01:22:00.690 --> 01:22:01.710 align:middle line:90%
how many a's are there?

01:22:01.710 --> 01:22:03.630 align:middle line:84%
It could be anywhere
between 0 and n.

01:22:03.630 --> 01:22:04.710 align:middle line:90%
How many b's are there?

01:22:04.710 --> 01:22:05.642 align:middle line:90%
Between 0 and n.

01:22:05.642 --> 01:22:06.600 align:middle line:90%
How many c's are there?

01:22:06.600 --> 01:22:07.800 align:middle line:90%
Between 0 and n.

01:22:07.800 --> 01:22:15.690 align:middle line:84%
So 26 numbers in
the range 0 to n--

01:22:15.690 --> 01:22:24.480 align:middle line:84%
I like to think of this as a
26-digit number base n plus 1.

01:22:24.480 --> 01:22:29.220 align:middle line:84%
We can map this
into base n plus 1.

01:22:29.220 --> 01:22:36.360 align:middle line:84%
And we get 26
digits In that base.

01:22:36.360 --> 01:22:39.907 align:middle line:84%
Another way to say it is
that the number of possible

01:22:39.907 --> 01:22:42.240 align:middle line:84%
combinations here-- how many
a's, how many b's, how many

01:22:42.240 --> 01:22:42.960 align:middle line:90%
c's--

01:22:42.960 --> 01:22:45.480 align:middle line:90%
is not even theta.

01:22:45.480 --> 01:22:51.120 align:middle line:84%
It is n plus 1, anything between
0 and n, to the power of 26.

01:22:51.120 --> 01:22:54.270 align:middle line:90%
This is a good polynomial.

01:22:54.270 --> 01:22:58.630 align:middle line:84%
So I can do stuff
like radix sort.

01:22:58.630 --> 01:23:01.300 align:middle line:90%


01:23:01.300 --> 01:23:02.200 align:middle line:90%
Cool.

01:23:02.200 --> 01:23:07.330 align:middle line:84%
So let me summarize a little
bit how we solve part a.

01:23:07.330 --> 01:23:10.440 align:middle line:84%
So I want to build a
data structure, which is,

01:23:10.440 --> 01:23:12.960 align:middle line:84%
for each value i,
I know I'm going

01:23:12.960 --> 01:23:17.610 align:middle line:84%
to end up serving these four
cards, or in general, k cards.

01:23:17.610 --> 01:23:20.915 align:middle line:84%
So for those cards, I
would like to compute

01:23:20.915 --> 01:23:23.040 align:middle line:84%
how many a's, how many b's,
how many c's are there?

01:23:23.040 --> 01:23:25.770 align:middle line:84%
And then just write
down this number.

01:23:25.770 --> 01:23:27.470 align:middle line:84%
This is a number
which I can write down

01:23:27.470 --> 01:23:32.020 align:middle line:84%
in at most 26 words, because we
can represent numbers between 0

01:23:32.020 --> 01:23:33.660 align:middle line:90%
and n in a single word.

01:23:33.660 --> 01:23:37.020 align:middle line:84%
That's the w is at
least log n assumption.

01:23:37.020 --> 01:23:38.520 align:middle line:90%
So it's constant size.

01:23:38.520 --> 01:23:41.130 align:middle line:84%
In a constant
number of numbers, I

01:23:41.130 --> 01:23:44.640 align:middle line:84%
can represent all I need to
know about a thing of size--

01:23:44.640 --> 01:23:46.480 align:middle line:90%
of length k here.

01:23:46.480 --> 01:23:49.088 align:middle line:84%
So I don't need to know
which letters is where.

01:23:49.088 --> 01:23:50.630 align:middle line:84%
I just need to know
the sorted order.

01:23:50.630 --> 01:23:53.490 align:middle line:84%
So I just need to know-- this
is called a frequency table--

01:23:53.490 --> 01:23:55.230 align:middle line:90%
how many a's, how many b's?

01:23:55.230 --> 01:23:59.010 align:middle line:84%
And so if I can compute those,
then given that representation

01:23:59.010 --> 01:24:02.130 align:middle line:84%
for starting at i, and
given that representation

01:24:02.130 --> 01:24:04.300 align:middle line:84%
for starting at j,
say, which would

01:24:04.300 --> 01:24:07.920 align:middle line:84%
be these two and these
two, I can compare them

01:24:07.920 --> 01:24:09.780 align:middle line:84%
by just comparing
those 26 numbers.

01:24:09.780 --> 01:24:11.370 align:middle line:84%
If they're all
equal, then they're

01:24:11.370 --> 01:24:13.230 align:middle line:90%
the same string after sorting.

01:24:13.230 --> 01:24:15.510 align:middle line:84%
And if there's any difference,
then they're different.

01:24:15.510 --> 01:24:17.343 align:middle line:84%
So that's how I could
do it in constant time

01:24:17.343 --> 01:24:19.410 align:middle line:84%
if I can compute
these representations.

01:24:19.410 --> 01:24:21.660 align:middle line:90%
And it's not hard to do that.

01:24:21.660 --> 01:24:24.420 align:middle line:84%
It's called a sliding window
technique, where you compute it

01:24:24.420 --> 01:24:26.640 align:middle line:90%
for the first k guys.

01:24:26.640 --> 01:24:29.370 align:middle line:84%
And then you remove this
item and add this item.

01:24:29.370 --> 01:24:32.010 align:middle line:84%
And just by incrementing
the counter for b,

01:24:32.010 --> 01:24:33.810 align:middle line:84%
decrementing the
counter for a, now

01:24:33.810 --> 01:24:37.180 align:middle line:84%
I know the representation
for these guys.

01:24:37.180 --> 01:24:39.690 align:middle line:84%
Make a copy of that, which is
a copy of those 26 numbers,

01:24:39.690 --> 01:24:40.530 align:middle line:90%
constant.

01:24:40.530 --> 01:24:43.110 align:middle line:90%
Then I add on c, remove b.

01:24:43.110 --> 01:24:49.530 align:middle line:84%
Then I add on a, remove c,
add on d, remove d, add on c,

01:24:49.530 --> 01:24:53.983 align:middle line:84%
remove b, and add
on d, and remove c.

01:24:53.983 --> 01:24:55.400 align:middle line:84%
Well, I got back
to the beginning.

01:24:55.400 --> 01:24:57.425 align:middle line:84%
So now I have
representation of those.

01:24:57.425 --> 01:25:00.000 align:middle line:84%
OK, so by sliding
this window, I'm

01:25:00.000 --> 01:25:02.640 align:middle line:90%
only changing at the two ends.

01:25:02.640 --> 01:25:03.690 align:middle line:90%
I add one guy on.

01:25:03.690 --> 01:25:05.580 align:middle line:84%
I increment one
of these counters.

01:25:05.580 --> 01:25:07.140 align:middle line:84%
I decrement one
of these counters.

01:25:07.140 --> 01:25:09.620 align:middle line:84%
So in constant time,
given the representation

01:25:09.620 --> 01:25:12.120 align:middle line:84%
of one of these substrings, I
can compute the representation

01:25:12.120 --> 01:25:13.095 align:middle line:90%
of the next one.

01:25:13.095 --> 01:25:14.760 align:middle line:84%
And that's how I,
in linear time,

01:25:14.760 --> 01:25:16.470 align:middle line:84%
can build such a
data structure that

01:25:16.470 --> 01:25:19.860 align:middle line:84%
lets me tell whether
any two hands are equal.

01:25:19.860 --> 01:25:23.040 align:middle line:84%
The next problem,
part b, is, given

01:25:23.040 --> 01:25:25.650 align:middle line:84%
all these
representations, can you

01:25:25.650 --> 01:25:27.892 align:middle line:84%
find which one is
the most common?

01:25:27.892 --> 01:25:29.850 align:middle line:84%
Because we were choosing
i uniformly at random,

01:25:29.850 --> 01:25:33.930 align:middle line:84%
I want to know what the most
likely hand that you get is.

01:25:33.930 --> 01:25:35.910 align:middle line:84%
And I think the
easiest way to say

01:25:35.910 --> 01:25:38.670 align:middle line:84%
this is you can do
that by radix sorting.

01:25:38.670 --> 01:25:40.180 align:middle line:84%
You take all these
representations.

01:25:40.180 --> 01:25:42.480 align:middle line:84%
They are nice numbers
in the range 0

01:25:42.480 --> 01:25:45.010 align:middle line:90%
to n plus 1 to the 26th power.

01:25:45.010 --> 01:25:47.490 align:middle line:84%
So I can just run radix
sort and sort them all.

01:25:47.490 --> 01:25:49.830 align:middle line:84%
And then with a single
scan through the array,

01:25:49.830 --> 01:25:51.990 align:middle line:84%
I can see which one
is the most common.

01:25:51.990 --> 01:25:53.120 align:middle line:90%
Or rather, I can--

01:25:53.120 --> 01:25:56.610 align:middle line:84%
in a single scan, I can compute,
OK, how many of the same things

01:25:56.610 --> 01:25:57.330 align:middle line:90%
are at the front?

01:25:57.330 --> 01:26:00.310 align:middle line:84%
If they're sorted, then all the
equal ones will be together.

01:26:00.310 --> 01:26:01.630 align:middle line:90%
So how many are there?

01:26:01.630 --> 01:26:03.550 align:middle line:90%
Then how many equal ones next?

01:26:03.550 --> 01:26:05.190 align:middle line:90%
And how many equal ones next?

01:26:05.190 --> 01:26:07.950 align:middle line:84%
Each time, comparing each
item to the previous one.

01:26:07.950 --> 01:26:11.400 align:middle line:84%
Then I get frequency counts
for all of these hands.

01:26:11.400 --> 01:26:13.770 align:middle line:84%
And then I do another scan
to find the most common one.

01:26:13.770 --> 01:26:16.980 align:middle line:84%
And I can do another scan to
find the lexically best one,

01:26:16.980 --> 01:26:19.005 align:middle line:90%
lexically last one.

01:26:19.005 --> 01:26:22.370 align:middle line:84%
And that's how you
solve problem 5.

01:26:22.370 --> 01:26:28.000 align:middle line:90%