Integer to English Words is a classic "annoying but easy" interview problem. There is no clever algorithm — the whole challenge is organizing the work so the special cases (teens, zeros, scale words) do not turn into spaghetti. The trick is to break the number into groups of three digits.
Problem. Given a non-negative integer num, convert it to its English-words spelling.
Example: num = 1234567 → "One Million Two Hundred Thirty Four Thousand Five Hundred Sixty Seven".
The number is guaranteed to be less than 2^31, so the largest scale word we ever need is Billion.
The slow way first
You could try to handle the whole number with one giant chain of if statements — "if it is in the millions, then... if the millions part has a hundreds digit, then...". That works for one example and collapses the moment you hit a number shaped differently. Every case (teens like 13, round numbers like 100, embedded zeros like 1000007) becomes a new branch. It is unmaintainable and easy to get wrong.
The question to ask: what is the smallest piece I actually know how to spell? The answer is a three-digit chunk (0–999). If I can spell any number under 1000, I can spell any number at all.
The idea: split into thousand-groups
Western number-reading already groups digits in threes: 1,234,567. So split the number into groups of three digits from the right. Each group has a fixed scale word: from the right, the groups are ones, Thousand, Million, Billion. Convert each 3-digit group to words with one small helper, then tack on its scale word.
The 3-digit helper itself is tiny: an optional "X Hundred" from the hundreds digit, then the remaining two digits (which need their own small lookup for teens and tens).
Walk through it
Step through the animation. The group pointer moves across the three chunks 1 | 234 | 567. For each chunk we spell the three digits, then append the scale word printed beneath it (Million, Thousand, none). The words string at the bottom grows until it holds the full phrase.
Pseudocode
if num is 0: return "Zero"
split num into 3-digit groups, most-significant first # [1, 234, 567]
line up scale words from the right: ..., Million, Thousand, ones
words = ""
for each (chunk, scale) in groups:
if chunk is 0: skip it
spell hundreds digit -> "X Hundred" (if nonzero)
spell the last two digits (teens / tens + ones)
if scale is not the ones group: append the scale word
return words trimmedThe Python solution
def number_to_words(num):
if num == 0:
return "Zero"
groups = chunk_into_thousands(num) # e.g. [1, 234, 567]
scales = ["Billion", "Million", "Thousand", ""]
scales = scales[len(scales) - len(groups):]
words = ""
for chunk, scale in zip(groups, scales):
if chunk == 0:
continue
h, rest = divmod(chunk, 100)
if h:
words += " " + ONES[h] + " Hundred"
words += " " + two_digits(rest) # tens + ones
if scale:
words += " " + scale
return words.strip()chunk_into_thousandsslices the number into 3-digit groups, most-significant first.scalesis sliced so the last group lines up with""(ones, no scale word) and each earlier group gets Thousand / Million / Billion.if chunk == 0: continueskips empty groups, so1000007does not print "Zero Thousand".divmod(chunk, 100)splits a chunk into its hundreds digithand the remaining two digitsrest.two_digits(rest)handles the only real special case — teens (13is "Thirteen", not "Tenty Three") and the tens words.- We
strip()at the end because every piece was added with a leading space.
Complexity
| Case | Time | Notes |
|---|---|---|
| Any 32-bit input | O(1) (fast) | at most 4 groups, fixed lookups |
| In terms of digits d | O(d) (moderate) | constant work per group |
O(1) (fast)Because a 32-bit integer has at most four thousand-groups, this is effectively constant time — the value is bounded. The "complexity" here is purely about clean code, not Big-O.
When this pattern shows up
When a formatting problem feels overwhelming, look for the natural unit and write a helper that handles just that unit. Spell one 3-digit chunk; spell one date field; format one currency group. Then the outer loop is trivial. Decomposition beats one giant branch every time.
Two classic bugs: forgetting that teens are special (11–19 are not "tenty-one" style), and printing
scale words for empty groups (1000000 must be "One Million", not "One Million Zero Thousand"). The
if chunk == 0: continue guard kills the second one.
Practice
For num = 1234567, what scale word is appended to the chunk 234, and what is the chunk 567 spelled as?
1. Why do we split the number into groups of three digits?
2. What is the purpose of the 'if chunk == 0: continue' line?
3. Which case makes the two-digit helper non-trivial?
4. What is the time complexity for a 32-bit integer input?