Integer to English Words
Recurse over thousands groups — each group of 3 digits converted to "hundreds tens units", suffixed by "Thousand"/"Million"/"Billion".
6 min read
math string recursion
Problem#
Convert a non-negative integer to its English-word representation.
Examples#
123→"One Hundred Twenty Three".12345→"Twelve Thousand Three Hundred Forty Five".
Constraints#
0 <= num <= 2^31 - 1.
Approach#
Split the number into groups of three digits (thousands). For each group emit “hundreds tens units” via lookup tables. Append the magnitude suffix per group.
Solution#
class Solution { vector<string> below20 = {"","One","Two","Three","Four","Five","Six","Seven","Eight","Nine","Ten","Eleven","Twelve","Thirteen","Fourteen","Fifteen","Sixteen","Seventeen","Eighteen","Nineteen"}; vector<string> tens = {"","","Twenty","Thirty","Forty","Fifty","Sixty","Seventy","Eighty","Ninety"}; string under1000(int n) { string s; if (n >= 100) { s += below20[n / 100] + " Hundred"; n %= 100; if (n) s += ' '; } if (n >= 20) { s += tens[n / 10]; n %= 10; if (n) s += ' '; } if (n > 0 && n < 20) s += below20[n]; return s; }public: string numberToWords(int num) { if (num == 0) return "Zero"; vector<string> suffix = {"", " Thousand", " Million", " Billion"}; string out; int idx = 0; while (num > 0) { int part = num % 1000; if (part) { string chunk = under1000(part) + suffix[idx]; out = chunk + (out.empty() ? "" : " ") + out; } num /= 1000; ++idx; } return out; }};func numberToWords(num int) string { if num == 0 { return "Zero" } below20 := []string{"", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Eleven", "Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen", "Seventeen", "Eighteen", "Nineteen"} tens := []string{"", "", "Twenty", "Thirty", "Forty", "Fifty", "Sixty", "Seventy", "Eighty", "Ninety"} suffix := []string{"", " Thousand", " Million", " Billion"} under1000 := func(n int) string { s := "" if n >= 100 { s += below20[n/100] + " Hundred" n %= 100 if n > 0 { s += " " } } if n >= 20 { s += tens[n/10] n %= 10 if n > 0 { s += " " } } if n > 0 && n < 20 { s += below20[n] } return s } out := "" idx := 0 for num > 0 { part := num % 1000 if part > 0 { chunk := under1000(part) + suffix[idx] if out == "" { out = chunk } else { out = chunk + " " + out } } num /= 1000 idx++ } return out}class Solution: def numberToWords(self, num: int) -> str: if num == 0: return "Zero" below20 = ["", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Eleven", "Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen", "Seventeen", "Eighteen", "Nineteen"] tens = ["", "", "Twenty", "Thirty", "Forty", "Fifty", "Sixty", "Seventy", "Eighty", "Ninety"] suffix = ["", " Thousand", " Million", " Billion"]
def under1000(n: int) -> str: s = "" if n >= 100: s += below20[n // 100] + " Hundred" n %= 100 if n > 0: s += " " if n >= 20: s += tens[n // 10] n %= 10 if n > 0: s += " " if 0 < n < 20: s += below20[n] return s
out = "" idx = 0 while num > 0: part = num % 1000 if part > 0: chunk = under1000(part) + suffix[idx] out = chunk if not out else chunk + " " + out num //= 1000 idx += 1 return outfunction numberToWords(num) { if (num === 0) return "Zero"; const below20 = ["", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Eleven", "Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen", "Seventeen", "Eighteen", "Nineteen"]; const tens = ["", "", "Twenty", "Thirty", "Forty", "Fifty", "Sixty", "Seventy", "Eighty", "Ninety"]; const suffix = ["", " Thousand", " Million", " Billion"];
function under1000(n) { let s = ""; if (n >= 100) { s += below20[Math.floor(n / 100)] + " Hundred"; n %= 100; if (n > 0) s += " "; } if (n >= 20) { s += tens[Math.floor(n / 10)]; n %= 10; if (n > 0) s += " "; } if (n > 0 && n < 20) { s += below20[n]; } return s; }
let out = ""; let idx = 0; while (num > 0) { const part = num % 1000; if (part > 0) { const chunk = under1000(part) + suffix[idx]; out = out === "" ? chunk : chunk + " " + out; } num = Math.floor(num / 1000); idx++; } return out;}class Solution { private static final String[] BELOW20 = {"", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Eleven", "Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen", "Seventeen", "Eighteen", "Nineteen"}; private static final String[] TENS = {"", "", "Twenty", "Thirty", "Forty", "Fifty", "Sixty", "Seventy", "Eighty", "Ninety"}; private static final String[] SUFFIX = {"", " Thousand", " Million", " Billion"};
private String under1000(int n) { StringBuilder s = new StringBuilder(); if (n >= 100) { s.append(BELOW20[n / 100]).append(" Hundred"); n %= 100; if (n > 0) s.append(" "); } if (n >= 20) { s.append(TENS[n / 10]); n %= 10; if (n > 0) s.append(" "); } if (n > 0 && n < 20) { s.append(BELOW20[n]); } return s.toString(); }
public String numberToWords(int num) { if (num == 0) return "Zero"; String out = ""; int idx = 0; while (num > 0) { int part = num % 1000; if (part > 0) { String chunk = under1000(part) + SUFFIX[idx]; out = out.isEmpty() ? chunk : chunk + " " + out; } num /= 1000; idx++; } return out; }}function numberToWords(num: number): string { if (num === 0) return "Zero"; const below20: string[] = ["", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Eleven", "Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen", "Seventeen", "Eighteen", "Nineteen"]; const tens: string[] = ["", "", "Twenty", "Thirty", "Forty", "Fifty", "Sixty", "Seventy", "Eighty", "Ninety"]; const suffix: string[] = ["", " Thousand", " Million", " Billion"];
const under1000 = (n: number): string => { let s = ""; if (n >= 100) { s += below20[Math.floor(n / 100)] + " Hundred"; n %= 100; if (n > 0) s += " "; } if (n >= 20) { s += tens[Math.floor(n / 10)]; n %= 10; if (n > 0) s += " "; } if (n > 0 && n < 20) { s += below20[n]; } return s; };
let out = ""; let idx = 0; while (num > 0) { const part = num % 1000; if (part > 0) { const chunk = under1000(part) + suffix[idx]; out = out === "" ? chunk : chunk + " " + out; } num = Math.floor(num / 1000); idx++; } return out;}Editorial#
The trick is keeping spaces clean. Build each thousand-group’s chunk, then prepend it to the accumulator with a single space separator only when both sides are non-empty. The num == 0 corner case must be special-cased — every other digit would produce an empty string.
Complexity#
- Time:
O(log n). - Space:
O(log n)for the output.
Concept revision#
Related#