172. Factorial Trailing Zeroes
Problem Description
Given an integer n
, you need to find how many trailing zeroes are in the factorial of n
(written as n!
).
A factorial n!
is the product of all positive integers from 1 to n
. For example:
5! = 5 × 4 × 3 × 2 × 1 = 120
(which has 1 trailing zero)10! = 3,628,800
(which has 2 trailing zeroes)
Trailing zeroes are the consecutive zeros at the end of a number. The key insight is that trailing zeroes are created by factors of 10, and since 10 = 2 × 5
, we need pairs of 2s and 5s in the prime factorization. Since there are always more factors of 2 than 5 in n!
, the number of trailing zeroes is determined by counting the factors of 5.
The solution counts all factors of 5 in the numbers from 1 to n
:
- Numbers divisible by
5
contribute one factor of 5 each - Numbers divisible by
25
(which is5²
) contribute an additional factor of 5 - Numbers divisible by
125
(which is5³
) contribute yet another factor of 5 - And so on...
The algorithm repeatedly divides n
by 5 and accumulates the quotients to get the total count of factors of 5, which equals the number of trailing zeroes in n!
.
Intuition
To understand where trailing zeroes come from, we need to think about what creates a zero at the end of a number. A trailing zero is produced when we multiply by 10, and 10 = 2 × 5
.
So in the factorial n!
, every time we have a pair of factors 2 and 5, we get a trailing zero. For example, in 5! = 120
, we have factors that include both 2 and 5, creating one trailing zero.
The key observation is that in any factorial, we'll always have more factors of 2 than factors of 5. Why? Because every even number contributes at least one factor of 2, and even numbers appear much more frequently than multiples of 5. Therefore, the limiting factor is always the number of 5s.
Now, how do we count the factors of 5 in n!
?
- Every 5th number (5, 10, 15, 20, ...) contributes at least one factor of 5
- Every 25th number (25, 50, 75, ...) contributes an extra factor of 5 (since
25 = 5²
) - Every 125th number contributes yet another factor of 5 (since
125 = 5³
) - And so on...
Taking n = 130
as an example:
⌊130/5⌋ = 26
numbers contribute their first factor of 5⌊130/25⌋ = 5
numbers contribute a second factor of 5⌊130/125⌋ = 1
number contributes a third factor of 5- Total factors of 5:
26 + 5 + 1 = 32
This pattern leads us to the elegant solution: keep dividing n
by 5 and sum up all the quotients. Each division tells us how many numbers contribute factors at each power of 5.
Solution Approach
The implementation follows directly from the mathematical insight that we need to count all factors of 5 in [1, n]
.
The algorithm uses a simple iterative approach:
-
Initialize a counter
ans
to 0 to store the total count of trailing zeroes. -
Use a while loop that continues as long as
n > 0
:- Divide
n
by 5 using integer division:n //= 5
- Add the result to our answer:
ans += n
- This new value of
n
represents how many numbers contribute factors at the current power of 5
- Divide
-
Return the accumulated count.
Let's trace through the algorithm with n = 130
:
- First iteration:
n = 130 // 5 = 26
,ans = 0 + 26 = 26
- This counts numbers divisible by
5¹
- This counts numbers divisible by
- Second iteration:
n = 26 // 5 = 5
,ans = 26 + 5 = 31
- This counts numbers divisible by
5²
(like 25, 50, 75, 100, 125)
- This counts numbers divisible by
- Third iteration:
n = 5 // 5 = 1
,ans = 31 + 1 = 32
- This counts numbers divisible by
5³
(like 125)
- This counts numbers divisible by
- Fourth iteration:
n = 1 // 5 = 0
, loop ends - Return
ans = 32
The beauty of this approach is that by repeatedly dividing by 5, we automatically account for all powers of 5. Numbers with multiple factors of 5 get counted multiple times, which is exactly what we want.
Time Complexity: O(log₅ n)
since we divide n
by 5 in each iteration until it becomes 0.
Space Complexity: O(1)
as we only use a constant amount of extra space.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's work through a small example with n = 25
to see how the solution finds trailing zeroes in 25!
.
First, let's understand what we're looking for. The number 25!
has trailing zeroes because it contains pairs of factors 2 and 5. Since factors of 2 are abundant (every even number contributes at least one), we only need to count factors of 5.
Step-by-step execution:
Starting with n = 25
and ans = 0
:
Iteration 1:
- Divide:
n = 25 // 5 = 5
- Add to answer:
ans = 0 + 5 = 5
- This counts: 5, 10, 15, 20, 25 (five numbers divisible by 5)
Iteration 2:
- Divide:
n = 5 // 5 = 1
- Add to answer:
ans = 5 + 1 = 6
- This counts the extra factor of 5 in 25 (since 25 = 5²)
Iteration 3:
- Divide:
n = 1 // 5 = 0
- Loop terminates (n = 0)
Result: ans = 6
Let's verify this makes sense:
- Numbers contributing one factor of 5: 5, 10, 15, 20 (four numbers)
- Numbers contributing two factors of 5: 25 (one number, since 25 = 5 × 5)
- Total factors of 5: 4 + 2 = 6
Therefore, 25!
has 6 trailing zeroes. You can verify: 25! = 15,511,210,043,330,985,984,000,000
which indeed has 6 trailing zeroes.
The algorithm elegantly counts all factors of 5 by repeatedly dividing by 5, automatically accounting for numbers that contain multiple factors of 5.
Solution Implementation
1class Solution:
2 def trailingZeroes(self, n: int) -> int:
3 """
4 Calculate the number of trailing zeroes in n! (n factorial).
5
6 Trailing zeroes are produced by factors of 10, which come from 2 * 5.
7 Since there are always more factors of 2 than 5 in n!,
8 we only need to count the number of times 5 appears as a factor.
9
10 The number of times 5 appears is: n//5 + n//25 + n//125 + ...
11
12 Args:
13 n: A non-negative integer
14
15 Returns:
16 The number of trailing zeroes in n!
17 """
18 # Initialize counter for trailing zeroes
19 trailing_zero_count = 0
20
21 # Count all factors of 5 in numbers from 1 to n
22 # Each iteration divides n by 5 to count higher powers of 5
23 while n > 0:
24 # Divide n by 5 to get the count of numbers divisible by current power of 5
25 n //= 5
26 # Add the count to total trailing zeroes
27 trailing_zero_count += n
28
29 return trailing_zero_count
30
1class Solution {
2 /**
3 * Calculate the number of trailing zeroes in n! (n factorial).
4 *
5 * Trailing zeroes are produced by factors of 10, and 10 = 2 * 5.
6 * Since there are always more factors of 2 than 5 in n!,
7 * we only need to count the number of factors of 5.
8 *
9 * @param n The input number to calculate factorial trailing zeroes
10 * @return The number of trailing zeroes in n!
11 */
12 public int trailingZeroes(int n) {
13 int trailingZeroCount = 0;
14
15 // Count all factors of 5 in numbers from 1 to n
16 // n/5 gives count of numbers divisible by 5
17 // n/25 gives count of numbers divisible by 25 (contributing an extra 5)
18 // n/125 gives count of numbers divisible by 125 (contributing another extra 5)
19 // And so on...
20 while (n > 0) {
21 n /= 5; // Integer division to get the count at current power of 5
22 trailingZeroCount += n; // Add the count to total
23 }
24
25 return trailingZeroCount;
26 }
27}
28
1class Solution {
2public:
3 int trailingZeroes(int n) {
4 // Count the number of trailing zeros in n factorial
5 // Trailing zeros come from factors of 10, which is 2 * 5
6 // Since there are always more factors of 2 than 5 in n!,
7 // we only need to count the number of factors of 5
8
9 int count = 0;
10
11 // Count factors of 5, 25, 125, 625, etc.
12 // n/5 gives factors of 5
13 // n/25 gives additional factors from numbers divisible by 25
14 // n/125 gives additional factors from numbers divisible by 125, and so on
15 while (n > 0) {
16 n /= 5;
17 count += n;
18 }
19
20 return count;
21 }
22};
23
1/**
2 * Calculates the number of trailing zeroes in n! (n factorial)
3 *
4 * The number of trailing zeroes is determined by the number of times 10 is a factor in n!
5 * Since 10 = 2 × 5, and there are always more factors of 2 than 5 in n!,
6 * we only need to count the number of factors of 5
7 *
8 * @param n - The input number to calculate factorial trailing zeroes for
9 * @returns The count of trailing zeroes in n!
10 */
11function trailingZeroes(n: number): number {
12 let trailingZeroCount: number = 0;
13
14 // Count all factors of 5 in numbers from 1 to n
15 // We divide by 5, 25, 125, etc. to count multiples of 5^1, 5^2, 5^3, etc.
16 while (n > 0) {
17 // Integer division by 5 to count multiples of current power of 5
18 n = Math.floor(n / 5);
19
20 // Add the count of multiples to our total
21 trailingZeroCount += n;
22 }
23
24 return trailingZeroCount;
25}
26
Time and Space Complexity
Time Complexity: O(log n)
The algorithm repeatedly divides n
by 5 until n
becomes 0. In each iteration, n
is reduced by a factor of 5 (n //= 5
). The number of iterations required is determined by how many times we can divide n
by 5 before reaching 0, which is ⌊log₅(n)⌋ + 1
iterations. Since log₅(n) = log(n)/log(5)
and constants are ignored in Big-O notation, the time complexity is O(log n)
.
Space Complexity: O(1)
The algorithm uses only a constant amount of extra space. It maintains two variables (ans
for accumulating the result and n
for the iteration), regardless of the input size. No additional data structures or recursive calls are used, so the space complexity is constant, O(1)
.
Common Pitfalls
1. Attempting to Calculate the Factorial First
A common mistake is trying to compute n!
first and then count the trailing zeroes. This approach fails for two critical reasons:
Why it's problematic:
- Factorial values grow extremely quickly (e.g.,
20! = 2,432,902,008,176,640,000
) - Integer overflow occurs even for relatively small values of
n
- Converting to string and counting zeroes is inefficient and unnecessary
Incorrect approach:
def trailingZeroes(self, n: int) -> int:
# DON'T DO THIS - causes overflow for large n
factorial = 1
for i in range(1, n + 1):
factorial *= i
# Count trailing zeroes
count = 0
while factorial % 10 == 0:
count += 1
factorial //= 10
return count
Correct approach: Use the mathematical insight that trailing zeroes come from factors of 5, avoiding factorial calculation entirely.
2. Only Counting Numbers Divisible by 5 Once
Another pitfall is counting each multiple of 5 only once, forgetting that numbers like 25, 125, etc., contribute multiple factors of 5.
Incorrect approach:
def trailingZeroes(self, n: int) -> int:
# This only counts each multiple of 5 once
return n // 5 # WRONG - misses higher powers of 5
For n = 130
, this would return 26
instead of the correct answer 32
, missing the extra factors from 25 (5²), 125 (5³), etc.
Correct approach: The iterative division ensures we count all powers of 5:
130 // 5 = 26
(numbers with at least one factor of 5)26 // 5 = 5
(numbers with at least two factors of 5)5 // 5 = 1
(numbers with at least three factors of 5)- Total:
26 + 5 + 1 = 32
3. Using Recursion Without Considering Stack Limitations
While recursion can solve this problem elegantly, it may cause stack overflow for extremely large values of n
in languages with limited stack size.
Potentially problematic recursive approach:
def trailingZeroes(self, n: int) -> int:
if n == 0:
return 0
return n // 5 + self.trailingZeroes(n // 5)
While this works correctly and is mathematically equivalent to the iterative solution, the iterative approach is generally preferred for better space efficiency and avoiding potential stack overflow issues.
A heap is a ...?
Recommended Readings
Math for Technical Interviews How much math do I need to know for technical interviews The short answer is about high school level math Computer science is often associated with math and some universities even place their computer science department under the math faculty However the reality is that you
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Want a Structured Path to Master System Design Too? Don’t Miss This!