Encode numbers as fixed-width base62 codes, hash a long URL to a 7-character code, and resolve collisions with a conditional insert instead of check-then-write.
The URL shortener of Day 1, chapter 4 stores one mapping, short_code → original_url (section 4.1). A 7-character code over the 62 characters a-z A-Z 0-9 gives 62^7, about 3.5 trillion codes (Week 1 capstone, Deep Dive 1). Build the two pieces every design needs, whichever way the number behind a code is produced:
1. Base62. encode(n, length=7) writes a non-negative integer as exactly length characters of ALPHABET (given: a-z, then A-Z, then 0-9, so a is the digit 0 and 9 is 61), most significant digit first and left-padded with a. decode(code) reverses it.
| Call | Returns |
|---|---|
encode(0) |
"aaaaaaa" |
encode(62) |
"aaaaaba" |
encode(62 ** 7 - 1) |
"9999999" |
decode("aaab") |
1 |
Raise ValueError when n is negative or doesn't fit in length characters, and when decode sees a character outside ALPHABET.
2. A hashing shortener with collision handling. UrlShortener(db, hash_fn, length=7, max_attempts=3):
| Method | Does |
|---|---|
shorten(long_url) |
returns the URL's code, storing it if it's new |
expand(code) |
the long URL, or None for an unknown code |
Candidate i (from 0) is encode(hash_fn(key_i) % 62 ** length, length), where key_0 is the URL itself and key_i is f"{long_url}#{i}" for i ≥ 1. For each candidate:
db.put_if_absent(code, long_url) returns True: the code is ours. Return it.False and db.get(code) is this URL: it was shortened before. Return the same code (no new row).False and the code belongs to another URL: a collision. Try the next candidate.After max_attempts candidates collide, raise TooManyCollisions (given) and store nothing.
Why put_if_absent and not "get, then put if empty": two servers can both see the code free and both write it, and the second write silently replaces the first user's link. A conditional insert, like the UNIQUE constraint on short_code in the capstone's Edge Case 1, lets exactly one of them win. The given FakeDB has no plain put, so the safe version is the only one you can write.
In JavaScript and TypeScript: encode(n, length = 7), decode(code), new UrlShortener(db, hashFn, length = 7, maxAttempts = 3) with shorten(longUrl) and expand(code) (null when unknown), db.putIfAbsent(code, url), and errors are thrown as RangeError (bad number or character) and TooManyCollisions.
The capstone hands each server a range of counter values and scrambles each value with a reversible permutation, so codes never collide and need no lookup. Hashing the URL instead needs no coordination at all and gives the same URL the same code, but it can collide, and collisions get more frequent as the space fills. The first follow-up compares the two.
Write your code, then run 3 example tests and 10 hidden tests. Each run is limited to 8 seconds: an infinite loop gets stopped and the runtime restarts, your code stays.