Facebook Pixel

3855. Sum of K-Digit Numbers in a Range

HardMathDivide and ConquerCombinatoricsNumber Theory
LeetCode ↗

Problem Description

You are given three integers l, r, and k.

Consider all possible integers made up of exactly k digits, where each digit is picked independently from the range [l, r] (both ends included). When 0 is part of this range, numbers are allowed to have leading zeros.

Your task is to compute the sum of all such numbers that can be formed. Because the result can be extremely large, return it modulo 10^9 + 7.

To understand what is being asked, think of building a number digit by digit. There are k positions, and each position can independently hold any value from l to r. This means the total count of distinct numbers is (r - l + 1)^k. The problem wants the sum of every single one of these numbers.

For example, the digit placed at position i (counting from the rightmost digit as position 0) contributes its value multiplied by 10^i. Since each position can take any digit in [l, r], and the remaining k - 1 positions can be filled in (r - l + 1)^(k - 1) ways each, every choice of digit at a fixed position appears many times across all formed numbers. Adding up these contributions across all positions and all digit choices gives the final answer.

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

How We Pick the Algorithm

Why Math / Bit Manipulation?

This problem maps to Math / Bit Manipulation through a short path in the full flowchart.

Math orbitmanipulation?yesSimulationorstraightforward?noMath / BitManipulation

Uses combinatorial math with fast exponentiation to compute sum of all k-digit numbers in a range.

Open in Flowchart

Intuition

A direct approach of generating every possible number is impossible, because the number of combinations is (r - l + 1)^k, which grows astronomically large. We need a smarter way that counts contributions instead of enumerating numbers.

The key insight is to think about how much each digit position contributes to the final sum. Instead of looking at whole numbers, let's focus on a single position i (where i is counted from the rightmost digit, starting at 0). A digit x placed at this position adds x * 10^i to whatever number it belongs to.

Now ask: for a fixed position i, how many times does a particular digit value x show up across all the numbers? If we lock digit x into position i, the other k - 1 positions are still free, and each of them can take any of the r - l + 1 possible digits. That gives (r - l + 1)^(k - 1) different numbers that all share the same digit x at position i.

So the total contribution of position i is:

(sum of all digit values from l to r) * 10^i * (r - l + 1)^(k - 1)

The sum of all digit values from l to r is just an arithmetic series, which equals (l + r) * (r - l + 1) / 2. Let's call this total. Notice that total and (r - l + 1)^(k - 1) do not depend on the position i at all, so they are the same constant factor for every position.

This means the answer is simply that constant factor multiplied by the sum of all the 10^i terms:

total * (r - l + 1)^(k - 1) * (10^0 + 10^1 + ... + 10^(k - 1))

The geometric series 10^0 + 10^1 + ... + 10^(k - 1) has a clean closed form: (10^k - 1) / 9. Putting it all together:

total * (r - l + 1)^(k - 1) * (10^k - 1) / 9

Since k can be as large as 10^9, we cannot compute the powers by looping. Fast power (binary exponentiation) lets us calculate (r - l + 1)^(k - 1) and 10^k quickly under the modulo. Finally, because we work modulo 10^9 + 7, division by 9 cannot be done directly. We replace it with multiplication by the modular inverse of 9, obtained through Fermat's little theorem as pow(9, mod - 2, mod).

Pattern Learn more about Math, Divide and Conquer and Combinatorics patterns.

Solution Approach

Solution 1: Math + Fast Power

We enumerate each digit x from the lowest position to the highest. Suppose the current position is the i-th digit (0-indexed), which contributes x * 10^i to the number. The remaining k - 1 digits each have r - l + 1 choices, so the contribution of the current position is x * 10^i * (r - l + 1)^(k - 1). Since x ranges over [l, r], the sum of all values of x is (l + r) * (r - l + 1) / 2. Therefore, the total sum of all such numbers is:

sum_{i=0}^{k-1} ( (l + r) * (r - l + 1) / 2 ) * (r - l + 1)^(k - 1) * 10^i

= ( (l + r) * (r - l + 1) / 2 ) * (r - l + 1)^(k - 1) * ( (10^k - 1) / 9 )

We translate this formula into code step by step:

  1. Count the range size. Let n = r - l + 1, the number of choices available for each digit.

  2. Sum of the digit values. The arithmetic series l + (l + 1) + ... + r equals (l + r) * n / 2. We compute total = (l + r) * n // 2 % mod. The integer division by 2 is safe here because one of (l + r) or n is always even, so the product is divisible by 2 before taking the modulo.

  3. Power of the remaining positions. Using fast power (binary exponentiation), we compute part1 = pow(n % mod, k - 1, mod), which represents (r - l + 1)^(k - 1) under the modulo. Python's built-in pow with three arguments performs this efficiently in O(log k) time.

  4. Geometric series numerator. The sum 10^0 + 10^1 + ... + 10^(k - 1) equals (10^k - 1) / 9. We first compute the numerator part2 = (pow(10, k, mod) - 1) % mod, again using fast power for 10^k.

  5. Handle division by 9 with modular inverse. Since we are working modulo 10^9 + 7 (a prime), we cannot divide directly. By Fermat's little theorem, the modular inverse of 9 is inv9 = pow(9, mod - 2, mod). Multiplying by inv9 is equivalent to dividing by 9 under the modulo.

  6. Combine all parts. The final answer is the product of all factors taken modulo mod:

    ans = total * part1 % mod ans = ans * part2 % mod ans = ans * inv9 % mod

The algorithm relies only on basic arithmetic and the fast power (binary exponentiation) pattern to handle the large exponents, since k can be up to 10^9. There are no loops over the digits or positions, so the overall time complexity is O(log k), dominated by the modular exponentiations, and the space complexity is O(1).

Example Walkthrough

Let's trace through the solution with a concrete example: l = 1, r = 2, k = 2.

Step 0: Understand what we're summing.

We need all 2-digit numbers where each digit is independently chosen from [1, 2]. There are (2 - 1 + 1)^2 = 2^2 = 4 such numbers. Let's list them explicitly so we have a ground truth to check against:

Tens digitUnits digitNumber
1111
1212
2121
2222

The brute-force sum is 11 + 12 + 21 + 22 = 66. Our formula should produce this same 66.

Step 1: Count the range size.

n = r - l + 1 = 2 - 1 + 1 = 2. Each position has 2 possible digit choices.

Step 2: Sum of the digit values.

The digits available are 1 and 2, so the arithmetic series sum is (l + r) * n / 2 = (1 + 2) * 2 / 2 = 3. So total = 3. (Indeed, 1 + 2 = 3.)

Step 3: Power of the remaining positions.

When we lock one digit into a fixed position, the other k - 1 = 1 position is free with n choices. So part1 = n^(k-1) = 2^1 = 2. This means each fixed digit-at-a-position appears in 2 distinct numbers.

Step 4: Geometric series numerator.

The positional weights are 10^0 + 10^1 = 1 + 10 = 11. Using the closed form, (10^k - 1) = 10^2 - 1 = 99, so part2 = 99.

Step 5: Division by 9.

The geometric series equals 99 / 9 = 11, matching the manual 1 + 10 = 11. (With a real modulus we'd multiply by the modular inverse of 9, but for this tiny example plain division works.)

Step 6: Combine all parts.

ans = total * part1 * part2 / 9
    = 3     * 2     * 99    / 9
    = 3 * 2 * 11
    = 66

Verification via contribution counting. Let's confirm the logic position by position:

  • Units position (i = 0, weight 1): digits 1 and 2 each appear in part1 = 2 numbers. Contribution = (1 + 2) * 2 * 10^0 = 3 * 2 * 1 = 6. (Check the table: units digits are 1, 2, 1, 2, summing to 6.)
  • Tens position (i = 1, weight 10): likewise contribution = (1 + 2) * 2 * 10^1 = 3 * 2 * 10 = 60. (Check the table: tens digits are 1, 1, 2, 2, summing to 6, times weight 10 = 60.)

Total = 6 + 60 = 66. ✓

This matches the brute-force result exactly, confirming that collapsing the enumeration into total * part1 * part2 * inv9 gives the correct sum without ever generating the individual numbers.

Solution Implementation

1class Solution:
2    def sumOfNumbers(self, l: int, r: int, k: int) -> int:
3        MOD = 10**9 + 7
4
5        # Count of integers in the inclusive range [l, r]
6        count = r - l + 1
7
8        # Sum of the arithmetic sequence from l to r:
9        # ((first + last) * count) / 2
10        arithmetic_sum = (l + r) * count // 2 % MOD
11
12        # n^(k - 1): accounts for the number of combinations
13        # contributed across the remaining (k - 1) positions
14        power_count = pow(count % MOD, k - 1, MOD)
15
16        # (10^k - 1) which, when divided by 9, yields the repunit 111...1 (k ones).
17        # The repunit represents repeating/concatenating each value across k digit-blocks.
18        repunit_numerator = (pow(10, k, MOD) - 1) % MOD
19
20        # Modular inverse of 9 using Fermat's Little Theorem,
21        # valid because MOD is prime: a^(MOD-1) ≡ 1 (mod MOD) => a^(MOD-2) ≡ a^(-1)
22        inverse_nine = pow(9, MOD - 2, MOD)
23
24        # Combine all factors under the modulus:
25        # answer = arithmetic_sum * count^(k-1) * (10^k - 1) / 9
26        answer = arithmetic_sum
27        answer = answer * power_count % MOD
28        answer = answer * repunit_numerator % MOD
29        answer = answer * inverse_nine % MOD
30
31        return answer
32
1class Solution {
2    // Modulus value commonly used to prevent integer overflow in results.
3    private static final int MOD = 1_000_000_007;
4
5    public int sumOfNumbers(int l, int r, int k) {
6        // Count of integers in the inclusive range [l, r].
7        long count = r - l + 1L;
8
9        // Arithmetic series sum of the range [l, r]:
10        // (l + r) * count / 2, taken modulo MOD.
11        // Division by 2 is done before taking the modulo because
12        // (l + r) * count is guaranteed to be even.
13        long rangeSum = (long) (l + r) * count / 2 % MOD;
14
15        // count^(k - 1) mod MOD.
16        // This accounts for the number of ways the remaining (k - 1)
17        // positions can be filled by values in the range.
18        long countPow = qpow(count % MOD, k - 1, MOD);
19
20        // (10^k - 1) mod MOD.
21        // This is the numerator of the repunit-like factor representing
22        // the place values 1, 10, 100, ... summed across k positions.
23        // Adding MOD before the final modulo guards against a negative result.
24        long placeValueNumerator = (qpow(10, k, MOD) - 1 + MOD) % MOD;
25
26        // Modular inverse of 9 using Fermat's little theorem:
27        // 9^(MOD - 2) mod MOD, valid because MOD is prime.
28        // Multiplying by inv9 is equivalent to dividing by 9, which
29        // converts (10^k - 1) into the geometric series sum (10^k - 1) / 9.
30        long inv9 = qpow(9, MOD - 2, MOD);
31
32        // Combine all factors step by step, applying the modulo each time.
33        long ans = rangeSum;
34        ans = ans * countPow % MOD;
35        ans = ans * placeValueNumerator % MOD;
36        ans = ans * inv9 % MOD;
37
38        return (int) ans;
39    }
40
41    /**
42     * Computes (base^exp) mod modulus using fast exponentiation (binary exponentiation).
43     *
44     * @param base    the base value
45     * @param exp     the exponent (assumed non-negative)
46     * @param modulus the modulus
47     * @return (base^exp) mod modulus
48     */
49    private int qpow(long base, int exp, int modulus) {
50        long result = 1;
51        base %= modulus;
52
53        // Process each bit of the exponent from least significant to most significant.
54        for (; exp > 0; exp >>= 1) {
55            // If the current lowest bit is set, multiply the result by the current base.
56            if ((exp & 1) == 1) {
57                result = result * base % modulus;
58            }
59            // Square the base for the next bit position.
60            base = base * base % modulus;
61        }
62
63        return (int) result;
64    }
65}
66
1class Solution {
2public:
3    int sumOfNumbers(int l, int r, int k) {
4        const int kMod = 1'000'000'007;
5
6        // Count of integers in the inclusive range [l, r].
7        long long count = 1LL * r - l + 1;
8
9        // Sum of the arithmetic sequence from l to r:
10        // ((l + r) * count / 2) % kMod.
11        long long rangeSum = 1LL * (l + r) * count / 2 % kMod;
12
13        // count^(k - 1) % kMod, contributing the scaling factor for the
14        // k-block construction.
15        long long countPow = qpow(count % kMod, k - 1, kMod);
16
17        // (10^k - 1) % kMod, the numerator of the repunit value.
18        long long repunitNumerator = (qpow(10, k, kMod) - 1 + kMod) % kMod;
19
20        // Modular inverse of 9 via Fermat's little theorem:
21        // 9^(kMod - 2) % kMod, used to divide by 9 under the modulus.
22        long long inverseOfNine = qpow(9, kMod - 2, kMod);
23
24        // Combine all factors modulo kMod:
25        // rangeSum * count^(k-1) * (10^k - 1) / 9.
26        long long answer = rangeSum;
27        answer = answer * countPow % kMod;
28        answer = answer * repunitNumerator % kMod;
29        answer = answer * inverseOfNine % kMod;
30
31        return static_cast<int>(answer);
32    }
33
34private:
35    // Fast modular exponentiation: computes (base^exponent) % mod
36    // in O(log(exponent)) time using binary exponentiation.
37    long long qpow(long long base, long long exponent, int mod) {
38        long long result = 1;
39        base %= mod;
40        while (exponent > 0) {
41            // If the current lowest bit is set, accumulate the current base.
42            if (exponent & 1) {
43                result = result * base % mod;
44            }
45            // Square the base for the next bit position.
46            base = base * base % mod;
47            exponent >>= 1;
48        }
49        return result;
50    }
51};
52
1const MOD = 1_000_000_007n;
2
3/**
4 * Fast modular exponentiation: computes (base ^ exp) % mod.
5 */
6function qpow(base: bigint, exp: bigint, mod: bigint): bigint {
7    base %= mod;
8    let result = 1n;
9    while (exp > 0n) {
10        // If the current lowest bit is set, multiply result by the current base.
11        if ((exp & 1n) === 1n) {
12            result = (result * base) % mod;
13        }
14        // Square the base for the next bit.
15        base = (base * base) % mod;
16        exp >>= 1n;
17    }
18    return result;
19}
20
21/**
22 * Computes the weighted sum of numbers from l to r, where each value is spread
23 * across k digit positions, returning the answer modulo 1e9+7.
24 */
25function sumOfNumbers(l: number, r: number, k: number): number {
26    // Count of integers in the inclusive range [l, r].
27    const count = BigInt(r - l + 1);
28
29    // Arithmetic series sum of [l, r]: ((l + r) * count) / 2, taken modulo MOD.
30    // The product (l + r) * count is always even, so integer division by 2 is exact.
31    const sum = ((BigInt(l + r) * count) / 2n) % MOD;
32
33    // count ^ (k - 1): the combinatorial factor for distributing values across positions.
34    const part1 = qpow(count % MOD, BigInt(k - 1), MOD);
35
36    // 10^k - 1: numerator of the repunit (111...1 with k ones); add MOD to stay non-negative.
37    const part2 = (qpow(10n, BigInt(k), MOD) - 1n + MOD) % MOD;
38
39    // Modular inverse of 9 via Fermat's little theorem, since (10^k - 1) / 9 = 111...1 (k ones).
40    const inv9 = qpow(9n, MOD - 2n, MOD);
41
42    // Combine all factors modulo MOD.
43    let ans = sum;
44    ans = (ans * part1) % MOD;
45    ans = (ans * part2) % MOD;
46    ans = (ans * inv9) % MOD;
47
48    return Number(ans);
49}
50

Time and Space Complexity

Time Complexity

The time complexity is O(log k).

The analysis is as follows:

  • Computing n = r - l + 1 and total = (l + r) * n // 2 % mod involves only basic arithmetic operations, each taking O(1) time.
  • part1 = pow(n % mod, k - 1, mod) uses fast modular exponentiation, which runs in O(log(k - 1)) = O(log k) time.
  • part2 = (pow(10, k, mod) - 1) % mod is another modular exponentiation taking O(log k) time.
  • inv9 = pow(9, mod - 2, mod) computes the Fermat inverse via modular exponentiation, taking O(log(mod)) time. Since mod = 10**9 + 7 is a fixed constant, this is O(1).
  • The final chain of multiplications and modulo operations are all O(1).

The dominant term comes from the exponentiations involving k, so the overall time complexity is O(log k).

Space Complexity

The space complexity is O(1).

Only a constant number of variables (mod, n, total, part1, part2, inv9, ans) are used, and the modular exponentiation pow with three arguments operates in constant extra space. No auxiliary data structures scale with the input, so the space complexity is O(1).

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

Common Pitfalls

Pitfall 1: Taking the Modulo Before the Integer Division by 2

The most common and subtle mistake is computing the arithmetic sum in the wrong order. It is tempting to write:

# WRONG: applying modulo before the division by 2
arithmetic_sum = (l + r) % MOD * count % MOD // 2

The problem is that integer division // and the modulo operation do not commute. The identity (l + r) * count / 2 is only guaranteed to be an integer because one of (l + r) or count is always even. Once you reduce (l + r) * count modulo 10^9 + 7, the reduced value may become odd, so the subsequent // 2 silently discards a remainder and produces a wrong answer.

Solution: Perform the exact integer division by 2 on the full product before reducing modulo MOD:

# CORRECT: divide by 2 first, then reduce
arithmetic_sum = (l + r) * count // 2 % MOD

Python's arbitrary-precision integers make this safe — (l + r) * count never overflows, so the exact division is always valid. Alternatively, if you prefer to stay fully in modular arithmetic, multiply by the modular inverse of 2 instead of using //:

inverse_two = pow(2, MOD - 2, MOD)
arithmetic_sum = (l + r) % MOD * (count % MOD) % MOD * inverse_two % MOD

Pitfall 2: Using pow(count, k - 1) When k Could Be 0

If the constraints allow k = 0 (or you fail to verify the lower bound), then k - 1 becomes -1. Python's three-argument pow(count % MOD, -1, MOD) interprets a negative exponent as a request for the modular inverse, not as (count)^(k-1) in the intended mathematical sense. This produces a meaningless result rather than an error.

Solution: Confirm from the constraints that k >= 1. If k = 0 is reachable, handle it explicitly — typically the empty number contributes 0, so return 0 directly:

if k == 0:
    return 0

Pitfall 3: Forgetting to Reduce count Before the Exponentiation

When r is large, count = r - l + 1 can exceed MOD. Passing a raw, un-reduced base into pow is not wrong in Python (it handles big integers), but mixing reduced and un-reduced values across the different factors can lead to inconsistent intermediate magnitudes and harder-to-debug code. The repunit and arithmetic terms are reduced mod MOD, so the base of the power should be too.

Solution: Always reduce the base explicitly, as the code does with count % MOD:

power_count = pow(count % MOD, k - 1, MOD)

This keeps every factor consistently in the range [0, MOD) and avoids accidental sign or magnitude issues when the formula is adapted or extended.


Pitfall 4: Misplacing the Modular Inverse of 9

A frequent error is dividing the geometric series by 9 using plain integer division:

# WRONG: (10^k - 1) is taken mod MOD first, so // 9 is invalid
repunit = (pow(10, k, MOD) - 1) // 9

After reducing 10^k - 1 modulo MOD, the result is generally not divisible by 9, so // 9 corrupts the value. The repunit (10^k - 1) / 9 is only an exact integer in true arithmetic, not in the reduced modular domain.

Solution: Replace the division with multiplication by the modular inverse of 9, valid because MOD is prime (Fermat's Little Theorem):

inverse_nine = pow(9, MOD - 2, MOD)
repunit = (pow(10, k, MOD) - 1) % MOD * inverse_nine % MOD

The same principle applies to any constant divisor in modular arithmetic — never use //, always multiply by the modular inverse.

Ready to land your dream job?

Unlock your dream job with a 5-minute quiz for a personalized study roadmap!

Get My Roadmap
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Get a Personalized Study Roadmap:

Consider the classic dynamic programming of longest increasing subsequence:

Find the length of the longest subsequence of a given sequence such that all elements of the subsequence are sorted in increasing order.

For example, the length of LIS for [50, 3, 10, 7, 40, 80] is 4 and LIS is [3, 7, 40, 80].

What is the recurrence relation?


Recommended Readings

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

Load More