372. Super Pow
Problem Description
You need to calculate a^b mod 1337
, where:
a
is a positive integerb
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
inb
(starting from the least significant), we multiply our result bya^e mod 1337
- After processing each digit, we update
a
toa^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
.
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:
- Start with the rightmost digit: compute
a^3
- Move to the next digit (2): we need
(a^10)^2
, so update our base toa^10
- 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:
-
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
- Set
-
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. -
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 computesa^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
toa^10 mod 1337
. This becomes our new base for the next iteration.
-
-
Return the final result: After processing all digits,
ans
containsa^b mod 1337
.
Example walkthrough with a = 2, b = [1, 0]
(representing 10):
- First iteration (digit 0):
ans = 1 * 2^0 % 1337 = 1
, thena = 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 EvaluatorExample 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 takesO(n)
iterations - Inside each iteration:
pow(a, e, mod)
performs modular exponentiation with exponente
(where0 ≤ e ≤ 9
), takingO(log e) = O(1)
time sincee
is at most 9pow(a, 10, mod)
performs modular exponentiation with exponent 10, takingO(log 10) = O(1)
time- The modulo operation
% mod
takesO(log m)
time
- Since we perform
O(log m)
operations for each of then
digits, the total time complexity isO(n × log m)
- Given that
m = 1337
is a constant, this simplifies toO(n)
Space Complexity: O(1)
- The algorithm uses only a constant amount of extra space for variables
mod
,ans
, anda
- The reversed iteration
b[::-1]
creates a reversed copy of arrayb
, which takesO(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 isO(1)
for the optimized version orO(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.
Which data structure is used to implement priority queue?
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
https assets algo monster cover_photos dnd svg Divide and Conquer The main idea of divide and conquer is to split the main problem into two smaller components assuming that each one of the components had already been solved recursively and then try to solve the bigger problem using the solutions
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
Want a Structured Path to Master System Design Too? Don’t Miss This!