Numerals and Parsing
What is this?
This is about translating numbers to and from the ways humans write them โ Roman numerals like MCMXCIV, the English words "one thousand two hundred", or a decimal you read off a string. Each notation is really just a small dictionary of symbols plus rules for how they combine. Parsing also means reading messy real-world text and pulling a clean number out of it.
๐ก Fun fact: A repeating decimal like 1/7 = 0.142857142857... never actually ends, but you can detect the loop in code by remembering each remainder you have already seen โ the moment one repeats, you have found the cycle.
๐ The 5 problems in this chapter are free. Sign in with Google or Microsoft to start solving.
Core idea: human number notations are just lookup tables plus rules for grouping and ordering, so converting them is a matter of greedily matching the largest piece, walking a remainder, and guarding the messy edge cases.
The pattern
Each problem here pairs a fixed vocabulary with a strategy for consuming or producing it. The recurring moves are: keep a value table sorted from largest to smallest and greedily subtract or emit the biggest piece that fits; group digits into fixed-size chunks so a small rule set covers an unbounded range; and run a state machine when raw text has optional signs, whitespace, or trailing junk.
The reason greedy works for these notations is that they are designed to be unambiguous from the top down โ the largest applicable symbol is always part of a valid representation. The reason parsing is fiddly is the opposite: real input is messy, and the hard work is rejecting or clamping what does not fit rather than the conversion itself. Long division adds a third idea โ track remainders to detect when a process repeats.
The problems
Integer to Roman uses a greedy value table that already includes the subtractive forms (4, 9, 40, 90, ...). Walk the table high to low, appending each symbol while it fits and subtracting its value, so the awkward cases need no special handling.
Roman to Integer scans left to right, adding each symbol's value but subtracting when a smaller symbol precedes a larger one โ that lone comparison captures every subtractive pair.
Integer to English Words groups the digits into threes (thousand, million, billion), names each group with one helper, and stitches the scale words between them โ turning an open-ended range into a tiny rule set.
Fraction to Recurring Decimal is long division: emit the integer part, then repeatedly multiply the remainder, recording each remainder in a map; the first repeat marks where the recurring block begins.
String to Integer (atoi) is a state machine: skip leading spaces, read an optional sign, consume digits, stop at the first non-digit, and clamp to the integer range on overflow.
Key takeaways
- A largest-first value table makes Roman conversions a clean greedy loop in both directions.
- Grouping digits into threes collapses arbitrarily large numbers into a handful of naming rules.
- Long division detects repetition by remembering remainders; a repeated remainder is a repeating decimal.
- Robust parsing is mostly edge-case discipline: signs, whitespace, trailing characters, and overflow clamping.
Core idea: Walk the string in a fixed order โ skip spaces, take at most one sign, eat digits until something isn't a digit, then clamp to the 32-bit range.
This problem looks trivial ("just turn a string into a number") and that's exactly the trap. The algorithm is easy; the discipline is hard. There's no clever trick to discover โ there's a precise sequence of rules, and your job is to honor every one of them without dropping an edge case on the floor.
Problem, rephrased
Imagine you're building the input box for a calculator app. A user pastes in whatever they have lying around โ maybe it has spaces from a copy-paste, maybe a stray sign, maybe trailing notes. You need to pull out the leading integer they meant, following exactly these rules:
- Skip leading spaces. Any number of
' 'at the front are ignored. - Take one optional sign. A single
'+'or'-'may follow. Not both. - Read digits
0โ9until you hit a non-digit. - Ignore everything after the digits (trailing junk doesn't matter).
- No digits found? Return
0. - Clamp the result into the 32-bit signed range
[-2^31, 2^31 - 1]=[-2147483648, 2147483647].
| Input | Output | Why |
|---|---|---|
"42" |
42 |
Plain digits. |
" -42" |
-42 |
Skip 3 spaces, take -, read 42. |
"4193 with words" |
4193 |
Read digits, stop at the space, ignore the rest. |
"words and 987" |
0 |
First real char is 'w' โ not a sign or digit. Stop. |
"-91283472332" |
-2147483648 |
Out of range below โ clamp to INT_MIN. |
"+-12" |
0 |
Two signs: after + the next char - isn't a digit. |
" +0 123" |
0 |
Read 0, stop at the space. The 123 is junk. |
Sign in to continue reading
The rest of this lesson is available with a free account. Signing in with Google or Microsoft is free.
Sign in to read the full lesson