Facebook Pixel

1922. Count Good Numbers

Problem Description

You need to count how many "good" digit strings can be formed with a given length n.

A digit string is considered good when:

  • Digits at even indices (0, 2, 4, ...) must be even numbers (0, 2, 4, 6, 8)
  • Digits at odd indices (1, 3, 5, ...) must be prime numbers (2, 3, 5, 7)

Note that indexing starts from 0.

For example:

  • "2582" is good because:

    • Index 0: 2 is even ✓
    • Index 1: 5 is prime ✓
    • Index 2: 8 is even ✓
    • Index 3: 2 is prime ✓
  • "3245" is not good because:

    • Index 0: 3 is odd (should be even) ✗

Given an integer n, you need to find the total number of good digit strings of length n. Since the result can be very large, return it modulo 10^9 + 7.

The key insight is that for a string of length n:

  • There are ⌈n/2⌉ positions at even indices, each can be filled with 5 choices (0, 2, 4, 6, 8)
  • There are ⌊n/2⌋ positions at odd indices, each can be filled with 4 choices (2, 3, 5, 7)

Therefore, the total count is: 5^(⌈n/2⌉) × 4^(⌊n/2⌋) mod (10^9 + 7)

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

When we look at this problem, we need to count valid combinations, not generate them. This is a classic combinatorics problem.

Let's think about building a good string position by position. For each position, we have independent choices that don't affect other positions:

  • At position 0 (even index): We can choose from 5 even digits (0, 2, 4, 6, 8)
  • At position 1 (odd index): We can choose from 4 prime digits (2, 3, 5, 7)
  • At position 2 (even index): Again 5 choices
  • At position 3 (odd index): Again 4 choices
  • And so on...

Since each position's choice is independent, we can use the multiplication principle. If we have a string of length 4, the total number of good strings would be 5 × 4 × 5 × 4.

We can see a pattern emerging:

  • For length 1: 5 (only one even-indexed position)
  • For length 2: 5 × 4
  • For length 3: 5 × 4 × 5 = 5² × 4
  • For length 4: 5 × 4 × 5 × 4 = 5² × 4²
  • For length 5: 5 × 4 × 5 × 4 × 5 = 5³ × 4²

The pattern shows that for a string of length n:

  • Number of even-indexed positions = ⌈n/2⌉ (ceiling of n/2)
  • Number of odd-indexed positions = ⌊n/2⌋ (floor of n/2)

Therefore, the total count becomes 5^(number of even positions) × 4^(number of odd positions).

Since the numbers can get very large, we use modular arithmetic and fast exponentiation to efficiently compute the result modulo 10^9 + 7.

Learn more about Recursion and Math patterns.

Solution Approach

The solution uses fast exponentiation to efficiently compute large powers modulo 10^9 + 7.

Based on our analysis, we need to calculate: ans=5n2×4n2ans = 5^{\lceil \frac{n}{2} \rceil} \times 4^{\lfloor \frac{n}{2} \rfloor}

Let's break down the implementation:

  1. Calculate the number of even and odd positions:

    • Even-indexed positions: ⌈n/2⌉ = ⌊(n+1)/2⌋
    • Odd-indexed positions: ⌊n/2⌋

    In the code, this is done using bit operations:

    • (n + 1) >> 1 is equivalent to ⌊(n+1)/2⌋ (right shift by 1 divides by 2)
    • n >> 1 is equivalent to ⌊n/2⌋
  2. Use Python's built-in pow function with three arguments:

    • pow(base, exponent, mod) efficiently computes base^exponent mod mod using fast exponentiation
    • This handles large exponents efficiently in O(log n) time
  3. Multiply the results:

    • First compute 5^(⌈n/2⌉) mod (10^9 + 7)
    • Then compute 4^(⌊n/2⌋) mod (10^9 + 7)
    • Multiply them together and take modulo again to get the final answer

The implementation:

def countGoodNumbers(self, n: int) -> int:
    mod = 10**9 + 7
    return pow(5, (n + 1) >> 1, mod) * pow(4, n >> 1, mod) % mod

This approach avoids overflow issues and runs in O(log n) time complexity due to the fast exponentiation algorithm, making it efficient even for very large values of n.

Ready to land your dream job?

Unlock your dream job with a 5-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's walk through the solution for n = 4 to see how we count good digit strings.

Step 1: Identify positions and their constraints For a string of length 4, we have positions [0, 1, 2, 3]:

  • Position 0 (even index): must be even digit → choices: {0, 2, 4, 6, 8} = 5 options
  • Position 1 (odd index): must be prime digit → choices: {2, 3, 5, 7} = 4 options
  • Position 2 (even index): must be even digit → choices: {0, 2, 4, 6, 8} = 5 options
  • Position 3 (odd index): must be prime digit → choices: {2, 3, 5, 7} = 4 options

Step 2: Count positions by type

  • Even-indexed positions: positions 0 and 2 → count = 2 = ⌈4/2⌉
  • Odd-indexed positions: positions 1 and 3 → count = 2 = ⌊4/2⌋

Step 3: Apply the multiplication principle Since each position's choice is independent:

  • Total = (choices for even positions)^(count of even positions) × (choices for odd positions)^(count of odd positions)
  • Total = 5² × 4² = 25 × 16 = 400

Step 4: Verify with code approach Using our formula with bit operations:

  • Even positions: (n + 1) >> 1 = (4 + 1) >> 1 = 5 >> 1 = 2
  • Odd positions: n >> 1 = 4 >> 1 = 2
  • Result: pow(5, 2, mod) * pow(4, 2, mod) % mod = 25 * 16 % mod = 400

Therefore, there are 400 good digit strings of length 4.

Some examples of valid strings: "0202", "2582", "4375", "8753" Example of invalid string: "1234" (position 0 has '1' which is odd, not even)

Solution Implementation

1class Solution:
2    def countGoodNumbers(self, n: int) -> int:
3        # Define the modulo constant for large number handling
4        MOD = 10**9 + 7
5      
6        # Calculate the count of even positions (0, 2, 4, ...)
7        # For n digits, there are (n + 1) // 2 even positions
8        even_positions = (n + 1) >> 1  # Equivalent to (n + 1) // 2
9      
10        # Calculate the count of odd positions (1, 3, 5, ...)
11        # For n digits, there are n // 2 odd positions
12        odd_positions = n >> 1  # Equivalent to n // 2
13      
14        # Even positions can have 5 choices: 0, 2, 4, 6, 8
15        # Odd positions can have 4 choices: 2, 3, 5, 7 (prime digits)
16        # Use modular exponentiation to compute large powers efficiently
17        even_count = pow(5, even_positions, MOD)
18        odd_count = pow(4, odd_positions, MOD)
19      
20        # Return the total count of good numbers
21        # Multiply the possibilities and apply modulo
22        return (even_count * odd_count) % MOD
23
1class Solution {
2    // Modulo value for preventing integer overflow
3    private final int MOD = 1000000007;
4
5    /**
6     * Counts the number of good digit strings of length n.
7     * A good digit string has:
8     * - Even indices (0, 2, 4, ...) containing even digits (0, 2, 4, 6, 8) - 5 choices
9     * - Odd indices (1, 3, 5, ...) containing prime digits (2, 3, 5, 7) - 4 choices
10     * 
11     * @param n the length of the digit string
12     * @return the count of good digit strings modulo 10^9 + 7
13     */
14    public int countGoodNumbers(long n) {
15        // Calculate the number of even positions: ceiling of n/2 = (n+1)/2
16        long evenPositions = (n + 1) >> 1;  // Equivalent to (n + 1) / 2
17      
18        // Calculate the number of odd positions: floor of n/2 = n/2
19        long oddPositions = n >> 1;  // Equivalent to n / 2
20      
21        // Total count = 5^evenPositions * 4^oddPositions
22        // Use modular exponentiation to handle large numbers
23        long result = modularPower(5, evenPositions) * modularPower(4, oddPositions) % MOD;
24      
25        return (int) result;
26    }
27
28    /**
29     * Calculates (base^exponent) % MOD using fast exponentiation.
30     * Time complexity: O(log n)
31     * 
32     * @param base the base number
33     * @param exponent the power to raise the base to
34     * @return (base^exponent) % MOD
35     */
36    private long modularPower(long base, long exponent) {
37        long result = 1;
38      
39        // Fast exponentiation algorithm
40        while (exponent != 0) {
41            // If exponent is odd, multiply result by base
42            if ((exponent & 1) == 1) {
43                result = result * base % MOD;
44            }
45          
46            // Square the base for the next iteration
47            base = base * base % MOD;
48          
49            // Divide exponent by 2
50            exponent >>= 1;  // Equivalent to exponent / 2
51        }
52      
53        return result;
54    }
55}
56
1class Solution {
2public:
3    int countGoodNumbers(long long n) {
4        const int MOD = 1000000007;  // 10^9 + 7 for modular arithmetic
5      
6        // Lambda function to calculate (base^exponent) % MOD using fast exponentiation
7        auto modularPower = [](long long base, long long exponent) -> long long {
8            long long result = 1;
9          
10            // Binary exponentiation algorithm
11            while (exponent > 0) {
12                // If current bit is 1, multiply result with base
13                if ((exponent & 1) == 1) {
14                    result = (result * base) % MOD;
15                }
16                // Square the base for next bit position
17                base = (base * base) % MOD;
18                // Right shift to process next bit
19                exponent >>= 1;
20            }
21          
22            return result;
23        };
24      
25        // Calculate the count of good numbers:
26        // - Even positions (0, 2, 4, ...) can have 5 choices (0, 2, 4, 6, 8)
27        // - Odd positions (1, 3, 5, ...) can have 4 choices (2, 3, 5, 7)
28        // - Number of even positions: (n + 1) / 2
29        // - Number of odd positions: n / 2
30        long long evenPositionCount = (n + 1) >> 1;  // Equivalent to (n + 1) / 2
31        long long oddPositionCount = n >> 1;         // Equivalent to n / 2
32      
33        // Total count = 5^(even positions) * 4^(odd positions) % MOD
34        return (modularPower(5, evenPositionCount) * modularPower(4, oddPositionCount)) % MOD;
35    }
36};
37
1/**
2 * Counts the number of good digit strings of length n.
3 * A digit string is good if:
4 * - Digits at even indices (0-indexed) are even (0, 2, 4, 6, 8)
5 * - Digits at odd indices are prime (2, 3, 5, 7)
6 * 
7 * @param n - The length of the digit string
8 * @returns The count of good numbers modulo 10^9 + 7
9 */
10function countGoodNumbers(n: number): number {
11    const MOD = 1000000007n;
12  
13    /**
14     * Performs modular exponentiation using binary exponentiation.
15     * Calculates (base^exponent) % MOD efficiently.
16     * 
17     * @param base - The base number
18     * @param exponent - The exponent
19     * @returns The result of (base^exponent) % MOD
20     */
21    const modularPower = (base: bigint, exponent: bigint): bigint => {
22        let result = 1n;
23      
24        // Process each bit of the exponent
25        while (exponent > 0n) {
26            // If current bit is 1, multiply result by base
27            if (exponent & 1n) {
28                result = (result * base) % MOD;
29            }
30            // Square the base for the next bit position
31            base = (base * base) % MOD;
32            // Right shift to process next bit
33            exponent >>= 1n;
34        }
35      
36        return result;
37    };
38  
39    // Calculate number of positions with even indices (5 choices: 0,2,4,6,8)
40    // For n positions, there are ceiling(n/2) even positions
41    const evenPositionCount = BigInt(n + 1) / 2n;
42    const evenPositionCombinations = modularPower(5n, evenPositionCount);
43  
44    // Calculate number of positions with odd indices (4 choices: 2,3,5,7)
45    // For n positions, there are floor(n/2) odd positions
46    const oddPositionCount = BigInt(n) / 2n;
47    const oddPositionCombinations = modularPower(4n, oddPositionCount);
48  
49    // Total combinations = even position combinations * odd position combinations
50    const totalCombinations = (evenPositionCombinations * oddPositionCombinations) % MOD;
51  
52    return Number(totalCombinations);
53}
54

Time and Space Complexity

The time complexity of this code is O(log n). This is because the built-in pow function with three arguments uses fast exponentiation (also known as exponentiation by squaring) to compute the modular exponentiation. Each call to pow(base, exponent, mod) takes O(log exponent) time. In this code:

  • pow(5, (n + 1) >> 1, mod) computes 5^⌈n/2⌉ mod (10^9 + 7) in O(log((n + 1) >> 1)) = O(log n) time
  • pow(4, n >> 1, mod) computes 4^⌊n/2⌋ mod (10^9 + 7) in O(log(n >> 1)) = O(log n) time

Since these operations are performed sequentially and then multiplied together, the overall time complexity remains O(log n).

The space complexity is O(1). The algorithm only uses a constant amount of extra space to store:

  • The mod variable
  • Intermediate results from the pow function calls
  • The final result before returning

The fast exponentiation algorithm implemented in Python's built-in pow function uses an iterative approach rather than recursive, so it doesn't consume additional stack space proportional to the input size.

Learn more about how to find time and space complexity quickly.

Common Pitfalls

1. Integer Overflow When Not Using Modular Arithmetic Properly

Pitfall: A common mistake is computing the powers first and then applying modulo at the end:

# WRONG approach - will cause overflow for large n
result = (5 ** even_positions) * (4 ** odd_positions) % MOD

This fails because 5^even_positions and 4^odd_positions can become astronomically large before the modulo operation, causing memory errors or overflow.

Solution: Use modular exponentiation throughout the calculation:

# CORRECT approach
even_count = pow(5, even_positions, MOD)
odd_count = pow(4, odd_positions, MOD)
result = (even_count * odd_count) % MOD

2. Incorrect Position Count Calculation

Pitfall: Confusing the count of even and odd positions:

# WRONG - swapped the calculations
even_positions = n // 2
odd_positions = (n + 1) // 2

For a string of length n:

  • When n=1: only position 0 (even) exists
  • When n=2: positions 0 (even) and 1 (odd) exist
  • When n=3: positions 0, 2 (even) and 1 (odd) exist

Solution: Remember that even positions always equal or exceed odd positions:

# CORRECT
even_positions = (n + 1) // 2  # Ceiling of n/2
odd_positions = n // 2          # Floor of n/2

3. Missing Final Modulo Operation

Pitfall: Forgetting to apply modulo after multiplication:

# WRONG - missing final modulo
return pow(5, even_positions, MOD) * pow(4, odd_positions, MOD)

Even though each pow() returns a value less than MOD, their product can exceed MOD.

Solution: Always apply modulo after multiplication:

# CORRECT
return (pow(5, even_positions, MOD) * pow(4, odd_positions, MOD)) % MOD

4. Using Custom Power Function Instead of Built-in

Pitfall: Implementing your own power function with modulo:

# INEFFICIENT and error-prone
def power_mod(base, exp, mod):
    result = 1
    for _ in range(exp):
        result = (result * base) % mod
    return result

This has O(n) time complexity and is much slower for large exponents.

Solution: Use Python's built-in pow(base, exp, mod) which implements fast exponentiation with O(log n) complexity:

# EFFICIENT
result = pow(base, exponent, MOD)
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

Which type of traversal does breadth first search do?


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More