Number of Digit One (LeetCode 233)
Add up how many times the digit 1 is written across all the whole numbers from 0 to n, both ends included. A number with several 1s, such as 11, counts each of them.
Worked Examples
n = 136n = 00⚖️Formal Constraints & Bounds
0 <= n <= 109
Core Insight
Numbers up to n can be built digit by digit, and every prefix only needs three facts to finish: its position, the 1s it holds, and whether it still equals n's prefix. Same facts, same future, so each state is counted once.
Real-World Scenario & Production Applications
Counting how many IDs, invoice numbers or ticket numbers in a range contain a given digit or pattern, for example to size a lookup table or to audit a numbering scheme, is the same count: the range is far too large to scan, but its limit can be walked digit by digit.
Step-by-Step Execution Trace Table
The trap case n = 190 (digits = [1, 9, 0]), at the calls where the tight bit matters. count(pos, ones, tight) returns the 1s in every number that finishes the prefix:
| Call | top | Digits tried | What happens |
|---|---|---|---|
count(0, 0, True) | 1 | 0, 1 | The first digit is 0 (numbers below 100) or 1 (100 to 190) |
count(1, 0, False) | 9 | 0..9 | After a 0 the prefix is already smaller than 190, so every second digit is free |
count(2, 0, False) | 9 | 0..9 | With tight and d == top, a 9 in the middle keeps the last digit free: 0..9 |
count(1, 1, True) | 9 | 0..9 | Still tight after the 1: the second digit may go up to 9 |
count(2, 1, True) | 0 | 0 | Tight after 1, 9: the last digit may only be 0 (the number 190) |
| End | count(0, 0, True) = 130 |
Staying tight on d == top alone would make count(2, 0, True) after the prefix 0, 9 cap the last digit at 0, dropping 91 and returning 129.
The Math, Step by Step
1. Every number as a string of digits
Let size be the number of digits of . Write every number from 0 to with exactly size digits, adding zeros on the left when it is shorter. For the numbers become 00, 01, ..., 13. The added zeros hold no 1, so the count of 1s does not change.
Now every number is one choice of a digit for each position, read from left to right. The code counts the 1s in all these digit strings that are at most .
The code's function count(pos, ones, tight) answers one question. Digits have already been chosen for positions 0 to pos - 1, and they hold ones digits equal to 1. Over every way to finish the string that keeps the number at most , how many 1s do the finished numbers hold in total? The answer to the whole problem is count(0, 0, True).
2. One step: choosing the digit at pos
The digit at position pos can be any value from 0 to top. Each choice adds to ones when :
Here is 1 when and 0 otherwise. At the end of the string, pos == size, and the finished number holds exactly ones 1s, so count returns ones.
The flag tight decides top:
tight | Meaning | top | tight for the next position |
|---|---|---|---|
True | the digits so far equal the first digits of | 's own digit, digits[pos] | True only if equals that digit |
False | the digits so far are already smaller than 's | 9 | False |
3. Why every number is counted once, and why memoization works
Two numbers with the same size digits compare like words in a dictionary. The first position where they differ decides which is smaller. So a string stays at most exactly when, at the first position where it leaves 's digits, it takes a smaller digit. The tight flag follows this rule. While tight is True, the digit may not exceed 's digit. Once a smaller digit is chosen, the number is already less than , and every later digit is free. So each number from 0 to is one path of choices, and no other path is allowed.
The answer of count depends only on its three arguments, not on which digits led there. So @lru_cache stores each answer once. There are at most size + 1 values of pos, at most size + 1 values of ones and 2 values of tight. Each state loops over at most 10 digits. This gives the docstring's time with = size.
A side note, not the code on this card: when tight is False, the free part has a closed form. Say = size - pos positions are left. Each of the endings adds the ones 1s already chosen. In each of the positions, the digit 1 appears in exactly of the endings. So the total is . Other solutions count, for each digit position of , how many numbers from 0 to have a 1 there. They use a formula built from the digits of above, at and below that position. The recursion on this card needs no such formula. It adds up the same counts one digit at a time.
4. The digit equal to top, and
tight and d == top keeps the flag only on the digit equal to top. If the code set the flag to True for every , it would forbid endings that are in the range. For it would then allow only 00, 10 and 20, and return 1 instead of 12. If it set the flag to False for every , it would allow endings above . For it would then also count 14 to 19, and return 12 instead of 6.
The loop is range(top + 1), so can equal top. The + 1 makes itself part of the count, as the problem's "from 0 to n, both ends included" requires.
For , digits is [0]. The only choice is , which holds no 1, so the code returns 0. This is Example 2.
5. Example 1 by hand
n = 13, so digits = [1, 3] and size = 2. The call count(0, 0, True) has top = 1, so it tries and .
| Call | top | Choices of the last digit | 1s in each finished number | Result |
|---|---|---|---|---|
count(1, 0, False), first digit 0 | 9 | 00 to 09 | 1 only for 01 | 1 |
count(1, 1, True), first digit 1 | 3 | 10, 11, 12, 13 | 1, 2, 1, 1 | 5 |
The first row is not tight, because 0 is smaller than 's first digit 1. So its last digit may be anything from 0 to 9. The second row is tight, because its first digit equals 's first digit. So its last digit may not pass 3. The side note agrees with the first row: with ones = 0 and , the total is .
count(0, 0, True) returns , the expected output. The six 1s are in 1, 10, 11 (two of them), 12 and 13.
6. From the recursion to the code
| Math | In countDigitOne |
|---|---|
| the digits of , left to right | digits = [int(c) for c in str(n)] |
a finished string holds ones 1s | if pos == size: followed by return ones |
| the largest digit allowed | top = digits[pos] if tight else 9 |
every digit from 0 to top | for d in range(top + 1): |
add one to ones when | ones + (d == 1) |
| stay tight only on 's own digit | tight and d == top |
| each state computed once | @lru_cache(maxsize=None) |
| start with no digits and tight | return count(0, 0, True) |
| 1 | Build every number up to `n` digit by digit from the most significant digit, and keep `tight`: whether the digits so far equal `n`'s. |
| 2 | `count(pos, ones, tight)` is the number of 1s in every number that finishes the prefix; a finished number adds its `ones`, and each allowed digit moves to `pos + 1`. |
| 3 | The shape: split `n` into its digits, a memoized count over (position, 1s so far, still tight), a base case at the end of the digits, a loop over the digits allowed at this position, and the call for position 0. |
| 4 | The trap: the next position is tight only when `tight and d == top`. `d == top` alone caps a number that was already smaller than `n`. |
Conceptual Narrative
🧭 Conceptual Foundation & Pattern Intuition
Counting something over every number from 0 to n is hopeless one number at a time when n is 10^9. Digit DP builds the numbers digit by digit instead, from the most significant digit, and keeps one bit of history about the limit: tight, whether every digit so far equals n's. While tight, the next digit may not pass n's digit; once a smaller digit has been placed, every later digit is free. Add the one fact the question needs, here ones, the 1s placed so far, and the whole count is a small table over (position, ones, tight).
🔢 The Analogy: A Combination Lock With a Maximum
Think of dialling every code up to a maximum on a lock, wheel by wheel. As long as the wheels you have set match the maximum, the next wheel may only go up to the maximum's digit. The moment one wheel is set lower, the rest can spin freely from 0 to 9. You never list the codes: you count how many ways each wheel can finish.
🔑 Why It Works
Two prefixes with the same (position, ones, tight) finish in exactly the same ways, so each state is solved once. The tight bit must pass on only when the prefix was tight and took n's digit: tight and d == top.
Staying tight on the digit alone: the next position is tight only when
tight and d == top. Usingd == topalone caps a number that was already smaller thann: after a0undern's1, a9would cap the next digit (n = 190gives 129 instead of 130).Using 9 as the top while tight:
top = digits[pos] if tight else 9. A tight prefix may not passn's digit here, or numbers abovenare counted.Counting numbers instead of 1s: the base case returns
ones, the 1s the finished number holds. Returning 1 counts the numbers, and a flag counts the numbers that contain a 1.Dropping
onesfrom the memo key:countdepends on how many 1s are already placed, so(pos, ones, tight)is the key. Caching on(pos, tight)alone reuses a total computed for a differentones.
4-Phase Thought Process Model
Pattern Recognition Signals
The 10-second spot
"Add up how many times the digit 1 is written across all the whole numbers from 0 to n" with n up to 10^9: a count over every number up to a limit, where the property depends only on the digits. Scanning is too slow, so walk the limit's digits: Digit DP.
Formulating the Predicate & Invariants
Turning intuition into a boolean rule
count(pos, ones, tight) is the number of 1s in every number that finishes a prefix of length pos holding ones 1s, where tight means the prefix equals n's. top = digits[pos] if tight else 9; each d in range(top + 1) moves to count(pos + 1, ones + (d == 1), tight and d == top); count(size, ones, _) = ones; the answer is count(0, 0, True).
Silent Failure Traps & Edge Cases
Where confident candidates still lose points
This problem's traps are in Common Pitfalls above.
The 60-Second Interview Pitch
Say this out loud before you type a single line
I'd use Digit DP. Scanning every number up to a billion is too slow, but the count only depends on the digits, so I build the numbers digit by digit from the front. A state is the position, how many 1s the prefix holds, and whether the prefix still equals n's, called tight. While tight, the next digit can only go up to n's digit there; otherwise it can be anything from 0 to 9. Each finished number adds its 1s. Prefixes with the same state finish the same way, so I memoize on all three. The trap is the tight bit: the next position stays tight only if this one was tight and took n's digit. Using the digit alone would cap a number that's already smaller than n. There are about D squared times two states with ten digits each, so O(D squared times 10) for D digits.
Complexity & Mathematical Proof
O(D^2 * 10)
Look at the code: count is memoized on (pos, ones, tight). pos runs from 0 to D, ones from 0 to D and tight is True or False, so there are at most (D + 1)^2 * 2 states. Each state runs for d in range(top + 1), at most 10 digits, with O(1) work per digit. Total: O(D^2 * 10). For n up to 10^9, D is at most 10, so this is a few thousand steps.
O(D^2)
The lru_cache keeps one entry per state, O(D^2), and the recursion goes at most D + 1 calls deep. digits holds D digits. The answer is one integer.
Derivation Progression
(D + 1) * (D + 1) * 2
pos from 0 to D, ones from 0 to D, and tight True or False; lru_cache solves each once.
at most 10 digits
for d in range(top + 1) tries at most 10 digits, each with one cached call and one addition.
O(D^2 * 10)
For n = 10^9, D = 10: at most 242 states and about 2,400 digit tries, against about 10^10 digit checks for the brute force.
Variable Definitions
The limit n
Number of digits of n (size in the code), at most 10
Memory Architecture & Bounds
O(D): the recursion goes one call per digit
O(D^2): the memo of (pos, ones, tight) states
O(1): one integer
Boundary Best / Worst Cases
for a one-digit n
with
State-Space & Subproblem DAG(Directed Acyclic Graph) Topology
Senior SWE Deconstruction & Hardware Caveats
Triggers: "all the whole numbers from 0 to n", "how many times the digit 1 is written", with n up to . A count over every number up to a limit where the property depends only on the digits: Digit DP over (position, the fact you need, tight).
, so digits. Checking every number is about digit checks; the digit walk has at most states with up to 10 digits each. The answer is below , so a 64-bit integer is needed in fixed-width languages.
A property that needs more history (digits used, previous digit, a running remainder) goes into the state, and the state count is what decides whether it still fits.
Number of Digit One (LeetCode 233)
Add up how many times the digit 1 is written across all the whole numbers from 0 to n, both ends included. A number with several 1s, such as 11, counts each of them.
Worked Examples
n = 136n = 00⚖️Formal Constraints & Bounds
0 <= n <= 109
Core Insight
Numbers up to n can be built digit by digit, and every prefix only needs three facts to finish: its position, the 1s it holds, and whether it still equals n's prefix. Same facts, same future, so each state is counted once.
Real-World Scenario & Production Applications
Counting how many IDs, invoice numbers or ticket numbers in a range contain a given digit or pattern, for example to size a lookup table or to audit a numbering scheme, is the same count: the range is far too large to scan, but its limit can be walked digit by digit.
Step-by-Step Execution Trace Table
The trap case n = 190 (digits = [1, 9, 0]), at the calls where the tight bit matters. count(pos, ones, tight) returns the 1s in every number that finishes the prefix:
| Call | top | Digits tried | What happens |
|---|---|---|---|
count(0, 0, True) | 1 | 0, 1 | The first digit is 0 (numbers below 100) or 1 (100 to 190) |
count(1, 0, False) | 9 | 0..9 | After a 0 the prefix is already smaller than 190, so every second digit is free |
count(2, 0, False) | 9 | 0..9 | With tight and d == top, a 9 in the middle keeps the last digit free: 0..9 |
count(1, 1, True) | 9 | 0..9 | Still tight after the 1: the second digit may go up to 9 |
count(2, 1, True) | 0 | 0 | Tight after 1, 9: the last digit may only be 0 (the number 190) |
| End | count(0, 0, True) = 130 |
Staying tight on d == top alone would make count(2, 0, True) after the prefix 0, 9 cap the last digit at 0, dropping 91 and returning 129.
The Math, Step by Step
1. Every number as a string of digits
Let size be the number of digits of . Write every number from 0 to with exactly size digits, adding zeros on the left when it is shorter. For the numbers become 00, 01, ..., 13. The added zeros hold no 1, so the count of 1s does not change.
Now every number is one choice of a digit for each position, read from left to right. The code counts the 1s in all these digit strings that are at most .
The code's function count(pos, ones, tight) answers one question. Digits have already been chosen for positions 0 to pos - 1, and they hold ones digits equal to 1. Over every way to finish the string that keeps the number at most , how many 1s do the finished numbers hold in total? The answer to the whole problem is count(0, 0, True).
2. One step: choosing the digit at pos
The digit at position pos can be any value from 0 to top. Each choice adds to ones when :
Here is 1 when and 0 otherwise. At the end of the string, pos == size, and the finished number holds exactly ones 1s, so count returns ones.
The flag tight decides top:
tight | Meaning | top | tight for the next position |
|---|---|---|---|
True | the digits so far equal the first digits of | 's own digit, digits[pos] | True only if equals that digit |
False | the digits so far are already smaller than 's | 9 | False |
3. Why every number is counted once, and why memoization works
Two numbers with the same size digits compare like words in a dictionary. The first position where they differ decides which is smaller. So a string stays at most exactly when, at the first position where it leaves 's digits, it takes a smaller digit. The tight flag follows this rule. While tight is True, the digit may not exceed 's digit. Once a smaller digit is chosen, the number is already less than , and every later digit is free. So each number from 0 to is one path of choices, and no other path is allowed.
The answer of count depends only on its three arguments, not on which digits led there. So @lru_cache stores each answer once. There are at most size + 1 values of pos, at most size + 1 values of ones and 2 values of tight. Each state loops over at most 10 digits. This gives the docstring's time with = size.
A side note, not the code on this card: when tight is False, the free part has a closed form. Say = size - pos positions are left. Each of the endings adds the ones 1s already chosen. In each of the positions, the digit 1 appears in exactly of the endings. So the total is . Other solutions count, for each digit position of , how many numbers from 0 to have a 1 there. They use a formula built from the digits of above, at and below that position. The recursion on this card needs no such formula. It adds up the same counts one digit at a time.
4. The digit equal to top, and
tight and d == top keeps the flag only on the digit equal to top. If the code set the flag to True for every , it would forbid endings that are in the range. For it would then allow only 00, 10 and 20, and return 1 instead of 12. If it set the flag to False for every , it would allow endings above . For it would then also count 14 to 19, and return 12 instead of 6.
The loop is range(top + 1), so can equal top. The + 1 makes itself part of the count, as the problem's "from 0 to n, both ends included" requires.
For , digits is [0]. The only choice is , which holds no 1, so the code returns 0. This is Example 2.
5. Example 1 by hand
n = 13, so digits = [1, 3] and size = 2. The call count(0, 0, True) has top = 1, so it tries and .
| Call | top | Choices of the last digit | 1s in each finished number | Result |
|---|---|---|---|---|
count(1, 0, False), first digit 0 | 9 | 00 to 09 | 1 only for 01 | 1 |
count(1, 1, True), first digit 1 | 3 | 10, 11, 12, 13 | 1, 2, 1, 1 | 5 |
The first row is not tight, because 0 is smaller than 's first digit 1. So its last digit may be anything from 0 to 9. The second row is tight, because its first digit equals 's first digit. So its last digit may not pass 3. The side note agrees with the first row: with ones = 0 and , the total is .
count(0, 0, True) returns , the expected output. The six 1s are in 1, 10, 11 (two of them), 12 and 13.
6. From the recursion to the code
| Math | In countDigitOne |
|---|---|
| the digits of , left to right | digits = [int(c) for c in str(n)] |
a finished string holds ones 1s | if pos == size: followed by return ones |
| the largest digit allowed | top = digits[pos] if tight else 9 |
every digit from 0 to top | for d in range(top + 1): |
add one to ones when | ones + (d == 1) |
| stay tight only on 's own digit | tight and d == top |
| each state computed once | @lru_cache(maxsize=None) |
| start with no digits and tight | return count(0, 0, True) |
| 1 | Build every number up to `n` digit by digit from the most significant digit, and keep `tight`: whether the digits so far equal `n`'s. |
| 2 | `count(pos, ones, tight)` is the number of 1s in every number that finishes the prefix; a finished number adds its `ones`, and each allowed digit moves to `pos + 1`. |
| 3 | The shape: split `n` into its digits, a memoized count over (position, 1s so far, still tight), a base case at the end of the digits, a loop over the digits allowed at this position, and the call for position 0. |
| 4 | The trap: the next position is tight only when `tight and d == top`. `d == top` alone caps a number that was already smaller than `n`. |
Conceptual Narrative
🧭 Conceptual Foundation & Pattern Intuition
Counting something over every number from 0 to n is hopeless one number at a time when n is 10^9. Digit DP builds the numbers digit by digit instead, from the most significant digit, and keeps one bit of history about the limit: tight, whether every digit so far equals n's. While tight, the next digit may not pass n's digit; once a smaller digit has been placed, every later digit is free. Add the one fact the question needs, here ones, the 1s placed so far, and the whole count is a small table over (position, ones, tight).
🔢 The Analogy: A Combination Lock With a Maximum
Think of dialling every code up to a maximum on a lock, wheel by wheel. As long as the wheels you have set match the maximum, the next wheel may only go up to the maximum's digit. The moment one wheel is set lower, the rest can spin freely from 0 to 9. You never list the codes: you count how many ways each wheel can finish.
🔑 Why It Works
Two prefixes with the same (position, ones, tight) finish in exactly the same ways, so each state is solved once. The tight bit must pass on only when the prefix was tight and took n's digit: tight and d == top.
Staying tight on the digit alone: the next position is tight only when
tight and d == top. Usingd == topalone caps a number that was already smaller thann: after a0undern's1, a9would cap the next digit (n = 190gives 129 instead of 130).Using 9 as the top while tight:
top = digits[pos] if tight else 9. A tight prefix may not passn's digit here, or numbers abovenare counted.Counting numbers instead of 1s: the base case returns
ones, the 1s the finished number holds. Returning 1 counts the numbers, and a flag counts the numbers that contain a 1.Dropping
onesfrom the memo key:countdepends on how many 1s are already placed, so(pos, ones, tight)is the key. Caching on(pos, tight)alone reuses a total computed for a differentones.
4-Phase Thought Process Model
Pattern Recognition Signals
The 10-second spot
"Add up how many times the digit 1 is written across all the whole numbers from 0 to n" with n up to 10^9: a count over every number up to a limit, where the property depends only on the digits. Scanning is too slow, so walk the limit's digits: Digit DP.
Formulating the Predicate & Invariants
Turning intuition into a boolean rule
count(pos, ones, tight) is the number of 1s in every number that finishes a prefix of length pos holding ones 1s, where tight means the prefix equals n's. top = digits[pos] if tight else 9; each d in range(top + 1) moves to count(pos + 1, ones + (d == 1), tight and d == top); count(size, ones, _) = ones; the answer is count(0, 0, True).
Silent Failure Traps & Edge Cases
Where confident candidates still lose points
This problem's traps are in Common Pitfalls above.
The 60-Second Interview Pitch
Say this out loud before you type a single line
I'd use Digit DP. Scanning every number up to a billion is too slow, but the count only depends on the digits, so I build the numbers digit by digit from the front. A state is the position, how many 1s the prefix holds, and whether the prefix still equals n's, called tight. While tight, the next digit can only go up to n's digit there; otherwise it can be anything from 0 to 9. Each finished number adds its 1s. Prefixes with the same state finish the same way, so I memoize on all three. The trap is the tight bit: the next position stays tight only if this one was tight and took n's digit. Using the digit alone would cap a number that's already smaller than n. There are about D squared times two states with ten digits each, so O(D squared times 10) for D digits.
Complexity & Mathematical Proof
O(D^2 * 10)
Look at the code: count is memoized on (pos, ones, tight). pos runs from 0 to D, ones from 0 to D and tight is True or False, so there are at most (D + 1)^2 * 2 states. Each state runs for d in range(top + 1), at most 10 digits, with O(1) work per digit. Total: O(D^2 * 10). For n up to 10^9, D is at most 10, so this is a few thousand steps.
O(D^2)
The lru_cache keeps one entry per state, O(D^2), and the recursion goes at most D + 1 calls deep. digits holds D digits. The answer is one integer.
Derivation Progression
(D + 1) * (D + 1) * 2
pos from 0 to D, ones from 0 to D, and tight True or False; lru_cache solves each once.
at most 10 digits
for d in range(top + 1) tries at most 10 digits, each with one cached call and one addition.
O(D^2 * 10)
For n = 10^9, D = 10: at most 242 states and about 2,400 digit tries, against about 10^10 digit checks for the brute force.
Variable Definitions
The limit n
Number of digits of n (size in the code), at most 10
Memory Architecture & Bounds
O(D): the recursion goes one call per digit
O(D^2): the memo of (pos, ones, tight) states
O(1): one integer
Boundary Best / Worst Cases
for a one-digit n
with
State-Space & Subproblem DAG(Directed Acyclic Graph) Topology
Senior SWE Deconstruction & Hardware Caveats
Triggers: "all the whole numbers from 0 to n", "how many times the digit 1 is written", with n up to . A count over every number up to a limit where the property depends only on the digits: Digit DP over (position, the fact you need, tight).
, so digits. Checking every number is about digit checks; the digit walk has at most states with up to 10 digits each. The answer is below , so a 64-bit integer is needed in fixed-width languages.
A property that needs more history (digits used, previous digit, a running remainder) goes into the state, and the state count is what decides whether it still fits.