How to Think Like a Computer

Enter the password to view this deck.

 

00:00
1 / 1
How to Think Like a Computer
YouBee.ai

How to Think Like a Computer

Hasan Nahleh, Founder of YouBee.ai

Press → to begin. That starts the clock

Two Different Machines

The gap between these two is the whole job.

You

  • See the whole picture at once
  • Intuition, pattern matching, "obviously"
  • Fill the gaps with common sense
  • Hold about 5 things at a time
VS

The Machine

  • One instruction at a time, in order
  • Zero intuition, zero context
  • Assumes nothing
  • 108 operations per second, forever

The "Click"

Somewhere in year two or three, something rewires. It isn't syntax. It's how a problem looks to you.

Before

"I know the answer. I just can't write it." Your solutions arrive as whole thoughts: find the biggest one, sort it, check if it's in there. All correct. All impossible to type.

The click

You stop trying to make the computer think like you, and start thinking like the computer.

The question changes from what is the answer to what are the steps. What do I look at? What must I remember? When do I stop?

After

Problems fall apart on their own: a loop here, a variable there, a comparison, an edge case. The code almost writes itself, because you were already thinking in it.

One mechanism. Every tooth in a fixed order.

The machine is never going to meet you halfway. It cannot learn your intuition or guess what you meant. So the move is not to teach it to think like you. It is to think like it.

One Number at a Time

Five numbers. Which is biggest? Click it and I'll time you. Then I take away the thing that made it easy.

The only thing the machine remembers
best =?
·
your time
0
machine comparisons
Five lines of code do exactly what you just did. They appear once the machine takes over.
int best = a[0];
for (int i = 1; i < a.length; i++)
if (a[i] > best)
best = a[i];
return best;

The Delivery Driver

Leave Nabatieh, deliver to Saida, Beirut and Tripoli. Shortest route? Click the cities. Distances are straight-line km.

·
this route, km
·
best, km
0
distances looked up
Click the cities in your driving order.
Routes you have tried

Is Brute Force the Answer?

No. You just watched all three. Same answer, 129 km, but look at what each one had to do to get there.

Try every ordering 18 lookups

Exact, and it checks all (n−1)! routes whether they look promising or not. Dies at about 12 cities.

Held–Karp 15 lookups

Also exact. It solves each set of cities once and reuses the answer, so it never re-walks a sub-route. Barely worth it at four cities. At fifteen it is 7 million steps against 87 billion routes.

Nearest neighbour 6 lookups

Give up on perfect. Grab the closest city and never look back. Three times less work than brute force here, and it scales to millions. This is the method your eyes used on the map.

Cost of option 1, trying every ordering
maproutestime
10 cities362,880instant
15 cities87 billion15 min
20 cities1.2×101738 years
25 cities6.2×1023196 Myr

Nobody knows a fast exact method, and nobody has proved one is impossible. That is the P vs NP question, with $1,000,000 attached.

So the question stops being "what is the answer?" and becomes "do I need it exact, or good and fast?"

The Method You Actually Used

Tracing that route, you followed one rule: from where I am, drive to the nearest place I have not been. Does it always work?

What your eyes do: always take the nearest
B you A C

start → A → B → C  =  1 + 4 + 13  =  18 km

The shortest route
B you A C

start → B → A → C  =  3 + 4 + 9  =  16 km

So: is it always right?

No. It took the cheap step in front of it and paid for that later.

On random maps it lands 20 to 25% over the best. On the Lebanese map it happened to be right, which is why it feels trustworthy.

Then why is it not worth $1,000,000?

It answers a different question. You asked for the shortest. This gives you a route.

Checking a route is under 20 km takes two additions. Checking it is the shortest means ruling out every other one. That gap is P vs NP.

Needle in the Haystack

Your eyes search in parallel. A CPU looks at one item at a time.

Can you spot the red dot? Click it.
Linear search: look at every one
for (int i = 0; i < dots.length; i++)
    if (dots[i] == "red")
        return i;
return -1;
0
checked
200
worst case

The dots are in no order. The only way to be sure is to look at every single one. Unsorted data costs you a look at all N.

Divide & Conquer

Pick a number 1–100. Don't tell me. I'll find it in 7 guesses or fewer.

Think of a number, then press Start Guessing.
low1
high100
mid–
steps0
int low = 1, high = 100;
while (low <= high) {
int mid = (low + high) / 2;
if (mid == answer)
return mid;
else if (mid < answer)
low = mid + 1;
else
high = mid - 1;
}

Every Guess Halves the World

Doubling the data costs you one extra guess. Not double the work. One guess.

Binary search only works on sorted data.
Sorted: looking for 21, you check 13
2591321344055

21 is bigger, so four of them are now impossible

Shuffled: looking for 21, you check 9
3424095513521

21 is bigger, so… nothing. It could still be anywhere.

Powers of two, not tens
list sizeguessesbecause
100727 = 128
1,00010210 = 1,024
1,000,00020220 ≈ 106
1,000,000,00030230 ≈ 109
The catch

"Can't I bin everything under 9 anyway?" Only after looking at all eight. And by then you have walked past 21.

Sorted data lets you discard what you never looked at. That is the whole saving.

So the sort is what buys the fast search. Pay once, search forever.

Sorting the Chaos

You sort it first. Shout at me and I'll swap two bars. Then we'll name what you invented.

Click two bars to swap them.
0
comparisons
0
swaps
~500k
comparisons at n=1,000

Everyone in this room invents one of the first three. Nobody invents Quick Sort by accident.

The Four Sorts, by the Numbers

Same job, same answer. Here is what each one actually costs as the list grows, counted in comparisons.

10 items1,0001,000,000
Bubble45500,0005×1011
Selection45500,0005×1011
Insertion~25250,0002.5×1011
Quick~24~10,000~20,000,000

At ten items they are all the same and none of it matters. At a million, the first three are not "slow". They are impossible. 5×1011 comparisons is about an hour and a half. Quick Sort finishes in a fifth of a second.

What actually separates them

The first three all compare every item against every other item. Double the list and you do four times the work.

Quick Sort splits the list in half, then halves the halves. Double the list and you do a bit more than twice the work. That is the same halving trick that beat the guessing game.

That difference, four times versus twice, is the only thing that matters at scale. Not the language, not the machine, not how tidy the code is.

These numbers are getting awkward to say out loud. Engineers gave the shapes names.

Giving It a Name: Big O

You have been counting operations all evening. Big O is just the shorthand. It names the shape of the growth, and throws away everything else.

shapewhat it meanswhere
O(1)always the same, however big the inputread a[7]
O(log n)halve it each step, so log2guessing game
O(n)look at each item oncered dot
O(n log n)halve it, and touch everything at each levelquick sort
O(n²)every item against every itembubble sort
O(n!)every possible orderingdelivery driver
How to read it

n is the size of the input: how many numbers, cities, dots or characters you were handed.

O(…) means "grows like". It is not a time in seconds. Two O(n) programs can differ by 50× and still both be O(n).

So it never answers "how fast is this?". It answers the only question that survives contact with real data: "what happens when n gets big?"

Careful with log. On a calculator log(100) is 2, because that is base 10. Halving means base 2: log2(100) ≈ 6.6, so 7 guesses. Big O writes no base at all, because changing base only multiplies by a constant and constants get dropped.

You already know all six. Five of them you did tonight, in this room, and the sixth is every array index you have ever written. This slide only gives them their names.

Time Complexity

Big O is not "how fast". It is how much worse it gets when the data grows.

At N = 1, at 108 ops/sec

The Three Rules of Big O

You can work out any complexity on paper with just these.

1
Drop the constants.
O(2n)→O(n) O(n/2 + 7)→O(n)
2
Keep only the biggest term.
O(n² + n)→O(n²) O(n + log n)→O(n)
3
Nested loops multiply. Sequential loops add.
for { for }→O(n²) for ; for→O(n)
Why throw away constants?

Because at real input sizes they stop mattering. At N = 1,000,000:

a sloppy O(n), 10× slow10,000,0000.1 s
a perfect O(n²)10122.8 hours

The badly written linear solution beats the beautifully tuned quadratic one by a factor of 100,000. The shape wins. Always.

The Constraints Tell You the Answer

One second of CPU time is about 108 operations. That is the budget for anything that has to feel instant: a page load, an API call, a contest submission. Take the biggest N you will be handed and see what survives.

Use it backwards: you see N ≤ 200,000, so O(N²) is dead, so you need sorting or a hash map, before writing one line of code.

Guess the Big O 1 of 8 Score 0

Shout it out.

Pick an answer to see why.

A Word on Space

Algorithms cost memory as well as time. It rarely decides the answer, but every machine you ship to has a ceiling.

O(1) extra space: in place
int tmp = a[i];   // one spare variable,
a[i] = a[j];      // whether the array holds
a[j] = tmp;       // 10 items or 10 million
O(n) extra space: a second copy
int[] out = new int[a.length];   // a whole new
for (int i = 0; i < a.length; i++)  // array, as big
    out[i] = f(a[i]);            // as the input
All you need to remember
  • An int is 4 bytes. A million of them is 4 MB.
  • A typical process gets a few hundred MB. 256 MB is a lot of room.
  • Recursion is not free: every live call keeps a frame.
  • Spending memory to buy time is usually the right trade.

A hash map turns an O(n²) scan into an O(n) pass by storing n things. That is a bargain, and it is the move you will reach for again and again.

The Toolbox

Four ways to hold your data. Forget the code for a minute: each one is a physical object, and each one makes a different question easy to ask.

01
Array / List
A numbered row of boxes. You ask for box 6, you get box 6.
Reach for it when the things have an order, or you want the nth one.
02
Hash Map
A wall of labelled drawers. You look things up by name, not by number.
Reach for it when you keep asking "have I seen this?" or "how many times?"
03
Stack
A pile of plates. You can only take the top one, the newest one.
Reach for it when the most recent thing has to be dealt with first.
04
Queue
The line at a bakery. Join the back, get served from the front.
Reach for it when everything must be handled in the order it arrived.

You already own all four in real life. Each one now gets a slide to explain it, a slide to watch it work, and a slide to practise it.

Array / List what it is

A row of boxes, all the same size, sitting next to each other. Numbered from 0, and the number is the whole trick.

What it is

One unbroken block of memory cut into equal boxes. Because they are equal and touching, the machine can work out where box 2 lives instead of looking for it. That is why the index is free and the content is not.

Two of them in Java
int[] a = new int[5];   // fixed size
a[2] = 85;
int n = a.length;

List<Integer> b = new ArrayList<>();
b.add(85);              // grows itself
int m = b.size();
You have used one already

The characters of a String. A board or grid, which is an array of arrays. The args handed to main. Every list you have looped over.

Array / List how it works

The simplest one there is: a numbered row of boxes, all the same size, side by side. Every other structure tonight is built out of this.

Click any box. Watch how the machine finds it.
address = 1000 + i × 4
·
read a[i]
·
append
·
insert at 0
Reach for it when
  • You want the nth thing, or all of them in order.
  • You will read far more often than you insert.
  • Scores you will sort, a board or a grid, the letters of a word.

Every box is the same size and they sit side by side, so the machine can calculate where box 6 is. That is also why inserting at the front is expensive: everything after it has to shuffle up to make room.

Exercise: How Many Boxes? 0 of 4 run

Ten boxes. For each job, say the number out loud before I run it.

Pick a job on the right. Let the room commit to a number first.

Four one-line jobs. Two of them are free. Two of them are not. Nothing in the source code tells you which is which, so you have to know the structure.

Hash Map what it is

A box of labelled drawers. You look things up by name instead of by number. If you have used a dictionary in Python or an associative array in PHP, you already know this one.

What it is

Hand it a key and it hands back the value filed under that key, without opening any other drawer. Ten entries or ten million, the answer costs the same.

In Java
Map<String,Integer> n = new HashMap<>();
n.put("Ali", 4);          // file it
n.get("Sara");            // 3
n.containsKey("Rita");    // true
n.getOrDefault("Zak", 0); // 0 if new
The habit worth building

About to write a loop that searches a list? Ask whether a map deletes the loop. It fixes more slow solutions than anything else tonight.

Hash Map: The Idea

An array can only be asked "what is in box 7?". A hash map can be asked "what is under the word grape?" and answers just as fast.

Type any word, a name, anything. Then press Hash it.
The whole trick, in one line
int slot = key.hashCode() % 8;
Reach for it when you hear yourself ask
  • "Have I seen this one before?" → containsKey
  • "How many times did each one turn up?" → a HashMap of counts
  • "Give me the record for this id." → a HashMap from id to thing

A hash map is an array. The only new part is the function that turns your key into an index. Nothing is ever searched, which is why it does not matter whether the map holds six words or six million.

What You Will Actually Write: Counting

Forget the hashing now, the library does it. Nine times out of ten a hash map is for one job: how many times did each thing turn up?

Ten votes came in. Count them one at a time.
count  name → how many
0
votes read
0
different names
The four calls you need
  • put(k, v) store it, or overwrite it
  • getOrDefault(k, 0) read it, or 0 the first time
  • containsKey(k) is it in there yet?
  • keySet() every key, to loop over at the end

Exercise: Has This Appeared Before?

Fourteen numbers, find the first one that repeats. Same loop both times. The only difference is where you keep what you have already seen.

Guess first: how many comparisons does each version need?
already seen
·
list, comparisons
·
map, lookups

One line different, and the shape of the whole program changes. This exact pattern turns up in more contest problems than any other.

Stack what it is

Last in, first out. A pile of plates. You put one on the top, you take one off the top, and the plate at the bottom is the one you get back last.

What makes it a stack

Both arrows point at the same end. You add at the top, you remove at the top, and you cannot touch anything else. That restriction is the whole point.

In Java
Deque<String> st = new ArrayDeque<>();
st.push("A");
st.push("B");
st.peek();        // "B", look, don't take
st.pop();         // "B", take it
st.isEmpty();
When the shape fits

Whenever the most recent thing must be dealt with first: undo, the back button, closing the bracket you opened last. And every recursive call you have made, because Java keeps this exact pile for you.

Stack how it works

Last in, first out. A pile of plates. Only the top one is reachable, and that limit is the whole feature.

Push a few items, then pop them back off.
0
height now
0
deepest it got
A stack you already write
int fact(int n) {
    if (n == 1) return 1;
    return n * fact(n - 1);
}
Reach for it when
  • Undo, a back button, anything that steps backwards.
  • Matching brackets, tags, nested anything.
  • Following one path to the end, then backing up to try another.
  • And every recursive method you have ever written.

Exercise: Balanced Brackets 1 of 5 Score 0

Valid or not? Vote first, then we step through it with a stack.

Hands up. Valid or not valid?
The whole checker
Stack<Character> st = new Stack<>();
for (char c : s.toCharArray()) {
  if (isOpen(c)) st.push(c);
  else {
    if (st.isEmpty()) return false;
    char open = st.pop();
    if (!pairs(open, c))
      return false;
  }
}
return st.isEmpty();

Counting the brackets is not enough. You have to remember which one you opened last and give it back first. That is a stack.

Queue what it is

First in, first out. The line at a bakery. You join at the back, you are served from the front, and nobody jumps.

What makes it a queue

The two arrows point at opposite ends. That is the only difference from a stack, and it changes everything: a stack deals with the newest first, a queue deals with the one that has waited longest.

In Java
Queue<String> q = new ArrayDeque<>();
q.add("A");       // join the back
q.add("B");
q.peek();         // "A", look, don't take
q.poll();         // "A", take it
q.isEmpty();
When the shape fits

Anything served in the order it arrived: print jobs, requests, whose turn it is. And the one that wins contests: spreading out in waves, which is how you find a shortest route.

Queue how it works

First in, first out. A bread line. You join the back, you are served from the front.

Add a few to the back, then serve from the front two different ways.
0
remove(0), items moved
0
head++, items moved
A queue that costs nothing
int[] q = new int[n];
int head = 0, tail = 0;
q[tail++] = x;     // join the back
int y = q[head++]; // serve the front
Reach for it when
  • Things are handled in the order they arrived: jobs, requests, turns.
  • You are spreading out level by level: shortest route, flood fill, how far away is it.

The trap: list.remove(0) shifts everyone left, so inside a loop it is quietly O(n²). Use ArrayDeque.

Exercise: Which One Do You Look At Next?

A maze. You start at S, the way out is E. The only decision in the whole algorithm: which cell do you look at next?

Click any dark cell to drop the start.
the frontier found but not explored yet, numbered by steps from S
Queue: oldest
Stack: newest
·
queue, steps to the exit
·
stack, steps to the exit

One word decides it. Take the oldest and the search spreads evenly, so the first time it touches the exit it has come the shortest way. Take the newest and it charges down one corridor until it is stuck. The data structure is the algorithm.

Two Sum: Brute Force, Then the Click

The problem: somewhere in this row, exactly two numbers add up to 17. Find which two, and report their positions.

Find the pair by eye first. Then watch the machine do it twice.
seen  value → index
empty
0
brute force, pairs tried
0
hash map, numbers read
Try every pair. O(N²) time, O(1) space
for (int i = 0; i < n; i++)
    for (int j = i+1; j < n; j++)
        if (a[i] + a[j] == T)
            return new int[]{i, j};
Remember what you passed. O(N) time, O(N) space
Map<Integer,Integer> seen = new HashMap<>();
for (int i = 0; i < n; i++) {
    int need = T - a[i];
    if (seen.containsKey(need))
        return new int[]{seen.get(need), i};
    seen.put(a[i], i);
}

Pseudocode First

Never jump from the idea straight to the syntax. Pseudocode is where you catch your own vagueness, before Java makes you commit to types.

Pseudocode not started

Java

The Bug Museum 1 of 7 Found 0

Click the line you think is broken.

What this code should do

Click a line of code.

Reading the Input

More points are lost to broken parsing than to bad algorithms. Copy your template now.

The input you'll be handed
2
5
1 2 3 4 5
3
10 20 30

Line 1: how many test cases. Then per case: N, then N numbers.

Traps
  • Sums over 2×109? Use long, not int
  • Scanner is fine to about 105 numbers. Past that use BufferedReader
  • Print exactly what's asked. No "Answer: "
  • int / int truncates. Cast before you divide

Warm-Up: Maximum Subarray

Find the contiguous block with the largest sum. Three minutes on paper. Go.

Three solutions, same answer. Watch the operation count collapse.
·
v1 steps
·
v2 steps
·
v3 steps

Contest Strategy

It isn't only who codes best. It's who spends their time best.

Questions? 8 in the bag

Anything from tonight, or anything you have been stuck on all semester.

Hands up. I will wait.
🏆

The Tournament Begins

Read the constraints. Find the brute force. Then find the click.

Java Syntax You Will Need

Six exercises tonight use five patterns. You already know the thinking. This is just the spelling.

Arrays: read, index, return, sort
int[] a = {4, 2, 6};
int first = a[0];
int n = a.length;
Arrays.sort(a);              // ascending, in place

return new int[]{i, j};      // return two indices
HashMap: count and look up
Map<String,Integer> count = new HashMap<>();
count.put("Ali", 1);
count.getOrDefault("Ali", 0);   // 0 if missing
count.containsKey("Ali");       // true / false

for (String key : count.keySet())
    System.out.println(key + " " + count.get(key));
Stack: last in, first out
Deque<Character> st = new ArrayDeque<>();
st.push('(');
st.peek();     // look, don't remove
st.pop();      // remove the top
st.isEmpty();
Comparing strings: never with ==
a.equals(b);      // same letters?
a.compareTo(b);   // negative = a comes first
Two traps that cost submissions
  • a == b on String compares references, not letters. Always .equals()
  • Factorials and big sums overflow int silently. Use long
Speaker notes