# The Number Narrator

> Every number has a story in words.

Canonical URL: <https://datadriven.io/problems/the_number_narrator>

Domain: Python · Difficulty: medium · Seniority: L4

## Problem

Given a non-negative integer (up to 999999), return its English word representation using standard naming. 0 returns 'Zero'. Use space as the separator (e.g., 123 -> 'One Hundred Twenty Three'). Use 'Hundred', 'Thousand' (no 'and'). Words are capitalized.

## Worked solution and explanation

### Why this problem exists in real interviews

This tests **recursive decomposition of a complex problem** into manageable chunks. Converting numbers to words requires handling ones, teens, tens, and scale words (thousand, million, billion), revealing whether candidates can design clean, layered logic.

---

### Break down the requirements

#### Step 1: Handle zero as a special case

Return 'Zero' immediately since it does not follow the standard decomposition.

#### Step 2: Define word mappings for ones, teens, and tens

Store lookup tables for numbers 1-19 and multiples of 10 from 20 to 90.

#### Step 3: Process the number in groups of three digits

Break the number into billions, millions, thousands, and remainder. Convert each group to words.

#### Step 4: Convert a three-digit group to words

Handle hundreds, then the remainder using teens (10-19) or tens + ones.

---

### The solution

**Chunk-based conversion with lookup tables**

```python
def number_to_words(num):
    if num == 0:
        return 'Zero'
    ones = ['', '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']
    def convert_chunk(n):
        parts = []
        if n >= 100:
            parts.append(ones[n // 100])
            parts.append('Hundred')
            n = n % 100
        if n >= 20:
            parts.append(tens[n // 10])
            n = n % 10
        if n > 0:
            parts.append(ones[n])
        return ' '.join(parts)
    scales = [(1000000000, 'Billion'), (1000000, 'Million'), (1000, 'Thousand')]
    parts = []
    for divisor, label in scales:
        if num >= divisor:
            parts.append(convert_chunk(num // divisor))
            parts.append(label)
            num = num % divisor
    if num > 0:
        parts.append(convert_chunk(num))
    result = ' '.join(parts)
    return result
```

> **Time and Space Complexity**
>
> **Time:** O(1). The number of digits is bounded (at most 10 for integers up to ~2 billion), so the work is constant.
> 
> **Space:** O(1). The lookup tables are fixed size.

> **Interviewers Watch For**
>
> Is your code organized into clean layers? The `convert_chunk` helper that handles a 3-digit group, called repeatedly for each scale, is the structure interviewers want to see.

> **Common Pitfall**
>
> Producing extra spaces when a chunk is zero (e.g., 1000000 has zero thousands and zero ones). Checking `if num >= divisor` before processing each scale prevents empty chunks from generating spurious labels.

---

## Common follow-up questions

- How would you extend this to handle decimals (e.g., 'Three Point One Four')? _(Tests splitting on the decimal point and converting each part.)_
- What about ordinal numbers (First, Second, Third)? _(Tests adding suffix rules for -st, -nd, -rd, -th.)_
- How would you handle negative numbers? _(Tests prepending 'Negative' and processing the absolute value.)_
- What if this ran in a hot loop processing millions of invoices? _(Tests caching or pre-computing common values.)_

## Related

- [All practice problems](https://datadriven.io/problems)
- [Mock interview mode](https://datadriven.io/interview/the_number_narrator)
- [Python Interview Questions](https://datadriven.io/python-interview-questions)
- [Data Engineering Interview Prep Guide](https://datadriven.io/data-engineer-interview-prep)
- [Daily Challenge](https://datadriven.io/daily)

---

Source: DataDriven (https://datadriven.io). 100% free data engineering interview prep. Live code execution against Postgres 16, Python 3.11, and Spark sandboxes. No paywall, no premium tier, no signup gate.