Facebook Pixel

372. Super Pow

Problem Description

You need to calculate a^b mod 1337, where:

  • a is a positive integer
  • b is an extremely large positive integer represented as an array of digits

For example, if b = [1, 2, 3], this represents the number 123.

The challenge is that b can be so large that it cannot fit in any standard integer data type, which is why it's given as an array of digits. You need to find the remainder when a raised to this massive power is divided by 1337.

The solution uses the property that a^(10*x + y) = (a^10)^x * a^y. By processing the digits of b from right to left, we can break down the large exponentiation into manageable pieces:

  • For each digit e in b (starting from the least significant), we multiply our result by a^e mod 1337
  • After processing each digit, we update a to a^10 mod 1337 to account for the next digit position (which represents a power 10 times larger)

This approach avoids computing the actual value of a^b (which would be astronomically large) and instead maintains all intermediate results modulo 1337.

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

Intuition

When faced with computing a^b mod 1337 where b is extremely large, the key insight is to decompose the exponent using positional notation.

Consider how we write numbers: 123 = 1×10² + 2×10¹ + 3×10⁰. This means a^123 = a^(100+20+3) = a^100 × a^20 × a^3.

We can rewrite this as: a^123 = (a^100) × (a^20) × (a^3) = ((a^10)^10)^1 × (a^10)^2 × a^3.

This reveals a pattern: if we process the digits from right to left, we can build up the result incrementally:

  1. Start with the rightmost digit: compute a^3
  2. Move to the next digit (2): we need (a^10)^2, so update our base to a^10
  3. Move to the next digit (1): we need ((a^10)^10)^1, so update our base again to (a^10)^10

The beauty of this approach is that at each step, we only need to:

  • Compute a^digit where digit is between 0-9 (small exponent)
  • Update our base by raising it to the 10th power for the next position

Since we're working with modular arithmetic, we can apply the mod operation at each step to keep numbers manageable. The property (x × y) mod m = ((x mod m) × (y mod m)) mod m ensures our intermediate results stay small while preserving correctness.

This transforms an impossible computation (raising a number to a power with hundreds of digits) into a series of simple operations with single-digit exponents.

Solution Approach

The implementation follows the mathematical decomposition we identified:

  1. Initialize variables:

    • Set mod = 1337 as our modulus
    • Initialize ans = 1 to accumulate our result
    • We'll process the digits of b in reverse order
  2. Process each digit from right to left:

    for e in b[::-1]:

    We reverse the array b to process digits from least significant to most significant.

  3. For each digit position:

    • Multiply the answer by a^e mod 1337:

      ans = ans * pow(a, e, mod) % mod

      This handles the contribution of the current digit. Python's built-in pow(a, e, mod) efficiently computes a^e mod 1337.

    • Update the base for the next digit position:

      a = pow(a, 10, mod)

      Since the next digit represents a power that's 10 times larger in magnitude, we transform a to a^10 mod 1337. This becomes our new base for the next iteration.

  4. Return the final result: After processing all digits, ans contains a^b mod 1337.

Example walkthrough with a = 2, b = [1, 0] (representing 10):

  • First iteration (digit 0): ans = 1 * 2^0 % 1337 = 1, then a = 2^10 % 1337 = 1024
  • Second iteration (digit 1): ans = 1 * 1024^1 % 1337 = 1024
  • Result: 2^10 mod 1337 = 1024

The algorithm runs in O(n) time where n is the number of digits in b, with each iteration performing constant-time modular exponentiation operations with small exponents (at most 10).

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 trace through the algorithm with a = 3 and b = [2, 3, 4] (representing 234).

We want to calculate 3^234 mod 1337.

Initial Setup:

  • mod = 1337
  • ans = 1
  • We'll process b in reverse: [4, 3, 2]

Iteration 1 (digit = 4, ones place):

  • Calculate contribution: ans = 1 * pow(3, 4, 1337) = 1 * 81 = 81
  • Update base for next position: a = pow(3, 10, 1337) = 59049 % 1337 = 168
  • After iteration 1: ans = 81, a = 168

Iteration 2 (digit = 3, tens place):

  • We need (3^10)^3 for the tens position
  • Calculate contribution: ans = 81 * pow(168, 3, 1337) % 1337
    • pow(168, 3, 1337) = 4741632 % 1337 = 1118
    • ans = 81 * 1118 % 1337 = 90558 % 1337 = 966
  • Update base for next position: a = pow(168, 10, 1337) = 1198
  • After iteration 2: ans = 966, a = 1198

Iteration 3 (digit = 2, hundreds place):

  • We need ((3^10)^10)^2 for the hundreds position
  • Calculate contribution: ans = 966 * pow(1198, 2, 1337) % 1337
    • pow(1198, 2, 1337) = 1435204 % 1337 = 202
    • ans = 966 * 202 % 1337 = 195132 % 1337 = 1131

Final Result: 3^234 mod 1337 = 1131

The key insight is how we build up the answer position by position:

  • Ones place: 3^4
  • Tens place: (3^10)^3
  • Hundreds place: ((3^10)^10)^2

Each iteration handles one digit while maintaining all calculations modulo 1337 to keep numbers manageable.

Solution Implementation

1class Solution:
2    def superPow(self, a: int, b: List[int]) -> int:
3        """
4        Calculate a^b mod 1337 where b is represented as an array of digits.
5      
6        The algorithm works by processing digits from right to left:
7        - For b = [1,2,3], we calculate a^123 = a^3 * (a^10)^2 * (a^100)^1
8        - Each iteration handles one digit and updates the base accordingly
9        """
10        MOD = 1337
11        result = 1
12      
13        # Process digits from least significant to most significant
14        for digit in reversed(b):
15            # Multiply result by a^digit for current position
16            result = (result * pow(a, digit, MOD)) % MOD
17          
18            # Update base for next position (multiply by 10 in exponent)
19            # a becomes a^10, then a^100, then a^1000, etc.
20            a = pow(a, 10, MOD)
21      
22        return result
23
1class Solution {
2    // Modulo value as specified in the problem
3    private final int MOD = 1337;
4
5    /**
6     * Computes a^b mod 1337 where b is an extremely large number represented as an array
7     * @param a The base number
8     * @param b The exponent represented as an array of digits (most significant digit first)
9     * @return The result of a^b mod 1337
10     */
11    public int superPow(int a, int[] b) {
12        long result = 1;
13      
14        // Process the exponent array from least significant digit to most significant
15        // For example, if b = [1,2,3], we compute a^123 = a^100 * a^20 * a^3
16        for (int i = b.length - 1; i >= 0; i--) {
17            // Multiply current result by a^(current digit)
18            result = result * quickPower(a, b[i]) % MOD;
19          
20            // Update base for next iteration: a becomes a^10
21            // This handles the positional value (units, tens, hundreds, etc.)
22            a = quickPower(a, 10);
23        }
24      
25        return (int) result;
26    }
27
28    /**
29     * Computes (base^exponent) mod 1337 using fast exponentiation (binary exponentiation)
30     * @param base The base number
31     * @param exponent The exponent value
32     * @return The result of (base^exponent) mod 1337
33     */
34    private long quickPower(long base, int exponent) {
35        long result = 1;
36      
37        // Binary exponentiation algorithm
38        // Repeatedly square the base and multiply when corresponding bit is 1
39        while (exponent > 0) {
40            // If current bit is 1, multiply result by current base
41            if ((exponent & 1) == 1) {
42                result = result * base % MOD;
43            }
44          
45            // Square the base for next iteration
46            base = base * base % MOD;
47          
48            // Right shift to process next bit
49            exponent >>= 1;
50        }
51      
52        return result;
53    }
54}
55
1class Solution {
2public:
3    int superPow(int a, vector<int>& b) {
4        using ll = long long;
5        const int MOD = 1337;
6      
7        // Lambda function for modular exponentiation
8        // Calculates (base^exponent) % MOD using binary exponentiation
9        auto modularPow = [&](ll base, int exponent) {
10            ll result = 1;
11          
12            // Binary exponentiation algorithm
13            while (exponent > 0) {
14                // If current bit is 1, multiply result by base
15                if (exponent & 1) {
16                    result = (result * base) % MOD;
17                }
18                // Square the base for next bit position
19                base = (base * base) % MOD;
20                // Move to next bit
21                exponent >>= 1;
22            }
23          
24            return static_cast<int>(result);
25        };
26      
27        ll result = 1;
28      
29        // Process digits from least significant to most significant
30        // For b = [d_n, d_{n-1}, ..., d_1, d_0], we compute:
31        // a^b = a^(d_0) * (a^10)^(d_1) * (a^100)^(d_2) * ...
32        for (int i = b.size() - 1; i >= 0; --i) {
33            // Multiply result by a^(current_digit)
34            result = (result * modularPow(a, b[i])) % MOD;
35          
36            // Update base for next iteration: a becomes a^10
37            a = modularPow(a, 10);
38        }
39      
40        return static_cast<int>(result);
41    }
42};
43
1/**
2 * Calculates a^b mod 1337 where b is represented as an array of digits
3 * @param a - The base number
4 * @param b - The exponent represented as an array of digits (e.g., 123 = [1,2,3])
5 * @returns The result of a^b mod 1337
6 */
7function superPow(a: number, b: number[]): number {
8    let result = 1;
9    const MOD = 1337;
10  
11    /**
12     * Fast exponentiation function to calculate (base^exponent) % MOD
13     * Uses binary exponentiation for efficiency
14     * @param base - The base number
15     * @param exponent - The exponent
16     * @returns (base^exponent) % MOD
17     */
18    const quickPower = (base: number, exponent: number): number => {
19        let powerResult = 1;
20      
21        // Binary exponentiation: process exponent bit by bit
22        while (exponent > 0) {
23            // If current bit is 1, multiply result by current base
24            if (exponent & 1) {
25                powerResult = Number((BigInt(powerResult) * BigInt(base)) % BigInt(MOD));
26            }
27            // Square the base for next bit position
28            base = Number((BigInt(base) * BigInt(base)) % BigInt(MOD));
29            // Shift exponent right by 1 bit
30            exponent >>= 1;
31        }
32      
33        return powerResult;
34    };
35  
36    // Process digits from least significant to most significant
37    // Uses the property: a^(10*d1 + d0) = (a^10)^d1 * a^d0
38    for (let i = b.length - 1; i >= 0; i--) {
39        // Multiply result by a^(current digit)
40        result = Number((BigInt(result) * BigInt(quickPower(a, b[i]))) % BigInt(MOD));
41        // Update base for next digit position (a becomes a^10)
42        a = quickPower(a, 10);
43    }
44  
45    return result;
46}
47

Time and Space Complexity

Time Complexity: O(n × log m) where n is the length of array b and m = 1337 is the modulus.

  • The main loop iterates through each digit in array b, which takes O(n) iterations
  • Inside each iteration:
    • pow(a, e, mod) performs modular exponentiation with exponent e (where 0 ≤ e ≤ 9), taking O(log e) = O(1) time since e is at most 9
    • pow(a, 10, mod) performs modular exponentiation with exponent 10, taking O(log 10) = O(1) time
    • The modulo operation % mod takes O(log m) time
  • Since we perform O(log m) operations for each of the n digits, the total time complexity is O(n × log m)
  • Given that m = 1337 is a constant, this simplifies to O(n)

Space Complexity: O(1)

  • The algorithm uses only a constant amount of extra space for variables mod, ans, and a
  • The reversed iteration b[::-1] creates a reversed copy of array b, which takes O(n) space
  • However, this can be optimized to O(1) by iterating from the end of the array without creating a copy
  • Excluding the input array b, the space complexity is O(1) for the optimized version or O(n) if using array reversal

Common Pitfalls

1. Forgetting to Update the Base a After Each Iteration

One of the most common mistakes is forgetting to update a to a^10 mod 1337 after processing each digit. This update is crucial because each digit position represents a power that's 10 times larger than the previous one.

Incorrect Implementation:

def superPow(self, a: int, b: List[int]) -> int:
    MOD = 1337
    result = 1
  
    for digit in reversed(b):
        result = (result * pow(a, digit, MOD)) % MOD
        # Missing: a = pow(a, 10, MOD)
  
    return result

This would incorrectly use the same base a for all digit positions, giving wrong results.

Solution: Always remember to update the base after processing each digit:

a = pow(a, 10, MOD)

2. Processing Digits in the Wrong Order

Another pitfall is processing the digits from left to right (most significant to least significant) without properly adjusting the logic. The algorithm relies on processing from right to left because we're building up from a^1 to a^10 to a^100, etc.

Incorrect Implementation:

def superPow(self, a: int, b: List[int]) -> int:
    MOD = 1337
    result = 1
  
    for digit in b:  # Wrong: processing from left to right
        result = (result * pow(a, digit, MOD)) % MOD
        a = pow(a, 10, MOD)
  
    return result

Solution: Either reverse the array or iterate backwards:

# Option 1: Reverse the array
for digit in reversed(b):
    # process digit

# Option 2: Iterate backwards
for i in range(len(b) - 1, -1, -1):
    digit = b[i]
    # process digit

3. Not Applying Modulo Operation Consistently

Failing to apply the modulo operation at every step can lead to integer overflow in languages with fixed integer sizes, or unnecessary large number computations.

Incorrect Implementation:

def superPow(self, a: int, b: List[int]) -> int:
    MOD = 1337
    result = 1
  
    for digit in reversed(b):
        result = result * pow(a, digit, MOD)  # Missing % MOD here
        a = pow(a, 10, MOD)
  
    return result % MOD  # Only applying mod at the end

While Python handles arbitrarily large integers, this approach is inefficient and in other languages could cause overflow.

Solution: Apply modulo after every multiplication to keep numbers small:

result = (result * pow(a, digit, MOD)) % MOD

4. Misunderstanding the Initial Value of result

Some might incorrectly initialize result to 0 or to a, thinking they need to start with the base or with nothing.

Incorrect Implementation:

result = 0  # Wrong: multiplication by 0 always gives 0
# or
result = a  # Wrong: this adds an extra factor of a

Solution: Always initialize result to 1 (the multiplicative identity):

result = 1

This ensures that the first multiplication correctly incorporates the first digit's contribution without adding extra factors.

Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

Which data structure is used to implement priority queue?


Recommended Readings

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

Load More