970. Powerful Integers
Problem Description
You need to find all powerful integers that are less than or equal to a given bound
.
A powerful integer is defined as any number that can be expressed as x^i + y^j
where:
x
andy
are given integersi
andj
are non-negative integers (i.e.,i ≥ 0
andj ≥ 0
)
Given three integers x
, y
, and bound
, your task is to return a list containing all powerful integers that have a value less than or equal to bound
. Each value should appear only once in the result (no duplicates), and the answer can be returned in any order.
For example, if x = 2
, y = 3
, and bound = 10
, the powerful integers would be:
2^0 + 3^0 = 1 + 1 = 2
2^0 + 3^1 = 1 + 3 = 4
2^1 + 3^0 = 2 + 1 = 3
2^1 + 3^1 = 2 + 3 = 5
2^2 + 3^0 = 4 + 1 = 5
(duplicate, not added again)2^2 + 3^1 = 4 + 3 = 7
2^0 + 3^2 = 1 + 9 = 10
2^3 + 3^0 = 8 + 1 = 9
The solution uses nested loops to generate all possible combinations of x^i
and y^j
, checking if their sum is within the bound. A set is used to automatically handle duplicates, and special care is taken for cases where x = 1
or y = 1
to avoid infinite loops.
Intuition
The key insight is that we need to find all possible sums of the form x^i + y^j
that don't exceed bound
. The most straightforward approach is to try different combinations of powers.
First, let's think about the range of values we need to check. Since we want x^i + y^j ≤ bound
, and the minimum value of y^j
is 1 (when j = 0
), we need x^i < bound
. This means we only need to consider values of i
where x^i < bound
.
For a number like x = 2
and bound = 1000000
, we notice that 2^20 = 1048576
, which exceeds our typical bound. This tells us that even for small bases, the exponent won't be very large - roughly at most 20 for base 2. For larger bases, the exponent limit becomes even smaller.
The natural approach is to use nested loops:
- The outer loop generates all possible values of
x^i
(let's call ita
) - The inner loop generates all possible values of
y^j
(let's call itb
) - For each combination, if
a + b ≤ bound
, thena + b
is a powerful integer
A special case to consider: when x = 1
or y = 1
, the corresponding power will always equal 1 regardless of the exponent. In this case, we only need one iteration for that base, otherwise we'd have an infinite loop.
Since the same powerful integer might be generated through different combinations (for example, 2^2 + 3^0 = 5
and 2^0 + 3^1 + 2^0 = 5
if we had three variables), we use a set to automatically eliminate duplicates. This ensures each powerful integer appears only once in our result.
Learn more about Math patterns.
Solution Approach
The implementation uses a hash table (set) to store unique powerful integers and nested loops to enumerate all possible combinations.
Algorithm Steps:
-
Initialize a set to store all powerful integers found. Using a set automatically handles duplicate values.
-
Outer loop for powers of x:
- Start with
a = 1
(which representsx^0
) - Continue while
a ≤ bound
(sincea + b
must be ≤bound
, and minimumb
is 1) - After each iteration, multiply
a
byx
to get the next power
- Start with
-
Inner loop for powers of y:
- For each value of
a
, start withb = 1
(which representsy^0
) - Continue while
a + b ≤ bound
- Add
a + b
to the set as it's a valid powerful integer - After each iteration, multiply
b
byy
to get the next power
- For each value of
-
Handle special cases:
- If
y = 1
, break the inner loop after the first iteration sincey^j
will always equal 1 - If
x = 1
, break the outer loop after completing all inner iterations sincex^i
will always equal 1
- If
-
Return the result by converting the set to a list.
Why this works:
The algorithm systematically generates all combinations where:
a
takes values:1, x, x^2, x^3, ...
up to the largest power less than or equal tobound
b
takes values:1, y, y^2, y^3, ...
up to the largest power wherea + b ≤ bound
Since we're checking every valid combination of x^i + y^j
within the bound, we're guaranteed to find all powerful integers. The set data structure ensures no duplicates in our final answer.
Time Complexity: O(log_x(bound) × log_y(bound))
in the worst case, since we iterate through at most log_x(bound)
powers of x
and log_y(bound)
powers of y
.
Space Complexity: O(min(bound, log_x(bound) × log_y(bound)))
for storing the unique powerful integers in the set.
Ready to land your dream job?
Unlock your dream job with a 3-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through the solution with x = 2
, y = 3
, and bound = 10
.
Step 1: Initialize
- Create an empty set to store powerful integers:
result_set = {}
Step 2: Start outer loop (powers of x = 2)
First outer iteration (a = 1, representing 2^0):
- Inner loop for powers of y = 3:
- b = 1 (3^0): Check 1 + 1 = 2 ≤ 10 ✓ → Add 2 to set:
{2}
- b = 3 (3^1): Check 1 + 3 = 4 ≤ 10 ✓ → Add 4 to set:
{2, 4}
- b = 9 (3^2): Check 1 + 9 = 10 ≤ 10 ✓ → Add 10 to set:
{2, 4, 10}
- b = 27 (3^3): Check 1 + 27 = 28 > 10 ✗ → Exit inner loop
- b = 1 (3^0): Check 1 + 1 = 2 ≤ 10 ✓ → Add 2 to set:
Second outer iteration (a = 2, representing 2^1):
- Inner loop for powers of y = 3:
- b = 1 (3^0): Check 2 + 1 = 3 ≤ 10 ✓ → Add 3 to set:
{2, 3, 4, 10}
- b = 3 (3^1): Check 2 + 3 = 5 ≤ 10 ✓ → Add 5 to set:
{2, 3, 4, 5, 10}
- b = 9 (3^2): Check 2 + 9 = 11 > 10 ✗ → Exit inner loop
- b = 1 (3^0): Check 2 + 1 = 3 ≤ 10 ✓ → Add 3 to set:
Third outer iteration (a = 4, representing 2^2):
- Inner loop for powers of y = 3:
- b = 1 (3^0): Check 4 + 1 = 5 ≤ 10 ✓ → Add 5 to set:
{2, 3, 4, 5, 10}
(5 already exists) - b = 3 (3^1): Check 4 + 3 = 7 ≤ 10 ✓ → Add 7 to set:
{2, 3, 4, 5, 7, 10}
- b = 9 (3^2): Check 4 + 9 = 13 > 10 ✗ → Exit inner loop
- b = 1 (3^0): Check 4 + 1 = 5 ≤ 10 ✓ → Add 5 to set:
Fourth outer iteration (a = 8, representing 2^3):
- Inner loop for powers of y = 3:
- b = 1 (3^0): Check 8 + 1 = 9 ≤ 10 ✓ → Add 9 to set:
{2, 3, 4, 5, 7, 9, 10}
- b = 3 (3^1): Check 8 + 3 = 11 > 10 ✗ → Exit inner loop
- b = 1 (3^0): Check 8 + 1 = 9 ≤ 10 ✓ → Add 9 to set:
Fifth outer iteration (a = 16, representing 2^4):
- Check: a = 16 > 10 → Exit outer loop
Step 3: Return result
Convert set to list: [2, 3, 4, 5, 7, 9, 10]
Notice how the set automatically handled the duplicate when we tried to add 5 twice (from 2^0 + 3^1 = 4 and 2^2 + 3^0 = 5). The algorithm efficiently explores all valid combinations while the bound constraint naturally limits our search space.
Solution Implementation
1class Solution:
2 def powerfulIntegers(self, x: int, y: int, bound: int) -> List[int]:
3 """
4 Find all powerful integers less than or equal to bound.
5 A powerful integer is a value that can be expressed as x^i + y^j
6 where i >= 0 and j >= 0.
7
8 Args:
9 x: Base for the first power
10 y: Base for the second power
11 bound: Upper limit for powerful integers
12
13 Returns:
14 List of all unique powerful integers <= bound
15 """
16 # Use set to store unique powerful integers
17 result_set = set()
18
19 # Initialize x^i starting from x^0 = 1
20 power_of_x = 1
21
22 # Iterate through all possible values of x^i
23 while power_of_x <= bound:
24 # Initialize y^j starting from y^0 = 1
25 power_of_y = 1
26
27 # Iterate through all possible values of y^j for current x^i
28 while power_of_x + power_of_y <= bound:
29 # Add the powerful integer to the result set
30 result_set.add(power_of_x + power_of_y)
31
32 # Calculate next power of y
33 power_of_y *= y
34
35 # Handle edge case: if y = 1, y^j will always be 1
36 # No need to continue inner loop
37 if y == 1:
38 break
39
40 # Calculate next power of x
41 power_of_x *= x
42
43 # Handle edge case: if x = 1, x^i will always be 1
44 # No need to continue outer loop
45 if x == 1:
46 break
47
48 # Convert set to list and return
49 return list(result_set)
50
1class Solution {
2 public List<Integer> powerfulIntegers(int x, int y, int bound) {
3 // Use HashSet to store unique powerful integers
4 Set<Integer> resultSet = new HashSet<>();
5
6 // Iterate through all possible powers of x (x^i where i >= 0)
7 // Starting with x^0 = 1, multiply by x each iteration
8 for (int powerOfX = 1; powerOfX <= bound; powerOfX *= x) {
9
10 // For each power of x, iterate through all possible powers of y (y^j where j >= 0)
11 // Starting with y^0 = 1, multiply by y each iteration
12 for (int powerOfY = 1; powerOfX + powerOfY <= bound; powerOfY *= y) {
13 // Add the sum of x^i + y^j to the result set
14 resultSet.add(powerOfX + powerOfY);
15
16 // Special case: if y = 1, then y^j will always be 1
17 // No need to continue the inner loop as it would be infinite
18 if (y == 1) {
19 break;
20 }
21 }
22
23 // Special case: if x = 1, then x^i will always be 1
24 // No need to continue the outer loop as it would be infinite
25 if (x == 1) {
26 break;
27 }
28 }
29
30 // Convert the HashSet to ArrayList and return
31 return new ArrayList<>(resultSet);
32 }
33}
34
1class Solution {
2public:
3 vector<int> powerfulIntegers(int x, int y, int bound) {
4 // Use unordered_set to store unique powerful integers
5 unordered_set<int> resultSet;
6
7 // Iterate through all possible powers of x (x^i)
8 // Starting from x^0 = 1, multiply by x each iteration
9 for (int powerOfX = 1; powerOfX <= bound; powerOfX *= x) {
10 // For each power of x, iterate through all possible powers of y (y^j)
11 // Starting from y^0 = 1, multiply by y each iteration
12 for (int powerOfY = 1; powerOfX + powerOfY <= bound; powerOfY *= y) {
13 // Add the sum of x^i + y^j to the result set
14 resultSet.insert(powerOfX + powerOfY);
15
16 // Special case: if y = 1, y^j will always be 1
17 // Avoid infinite loop by breaking after first iteration
18 if (y == 1) {
19 break;
20 }
21 }
22
23 // Special case: if x = 1, x^i will always be 1
24 // Avoid infinite loop by breaking after first iteration
25 if (x == 1) {
26 break;
27 }
28 }
29
30 // Convert the unordered_set to a vector and return
31 return vector<int>(resultSet.begin(), resultSet.end());
32 }
33};
34
1/**
2 * Finds all powerful integers less than or equal to bound.
3 * A powerful integer is a number that can be expressed as x^i + y^j where i >= 0 and j >= 0.
4 *
5 * @param x - First base number
6 * @param y - Second base number
7 * @param bound - Upper limit for powerful integers
8 * @returns Array of unique powerful integers within the bound
9 */
10function powerfulIntegers(x: number, y: number, bound: number): number[] {
11 // Use Set to store unique powerful integers
12 const powerfulNumbersSet = new Set<number>();
13
14 // Iterate through all possible powers of x
15 for (let powerOfX = 1; powerOfX <= bound; powerOfX *= x) {
16 // Iterate through all possible powers of y
17 for (let powerOfY = 1; powerOfX + powerOfY <= bound; powerOfY *= y) {
18 // Add the sum of current powers to the set
19 powerfulNumbersSet.add(powerOfX + powerOfY);
20
21 // If y is 1, y^j will always be 1, so break to avoid infinite loop
22 if (y === 1) {
23 break;
24 }
25 }
26
27 // If x is 1, x^i will always be 1, so break to avoid infinite loop
28 if (x === 1) {
29 break;
30 }
31 }
32
33 // Convert Set to Array and return
34 return Array.from(powerfulNumbersSet);
35}
36
Time and Space Complexity
Time Complexity: O(log²(bound))
The analysis involves two nested loops:
- The outer loop iterates while
a ≤ bound
. Sincea
starts at 1 and multiplies byx
each iteration (whenx > 1
), it runs at mostlog_x(bound)
times. Whenx = 1
, it runs only once due to the break statement. - The inner loop iterates while
a + b ≤ bound
. Sinceb
starts at 1 and multiplies byy
each iteration (wheny > 1
), it runs at mostlog_y(bound)
times. Wheny = 1
, it runs only once due to the break statement.
In the worst case when both x > 1
and y > 1
, the total number of iterations is log_x(bound) × log_y(bound)
, which can be expressed as O(log²(bound))
since both logarithms are bounded by log(bound)
.
Space Complexity: O(log²(bound))
The space is primarily used by the ans
set which stores all unique powerful integers. In the worst case, each combination of powers (x^i, y^j)
where x^i + y^j ≤ bound
produces a unique sum. The maximum number of such pairs is approximately log_x(bound) × log_y(bound)
, resulting in O(log²(bound))
space complexity.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Infinite Loop with Base Value of 1
The most critical pitfall is not handling the special case when x = 1
or y = 1
. When either base is 1, multiplying by 1 keeps the power constant, leading to an infinite loop.
Problematic Code:
# Without breaks for x=1 or y=1 while power_of_x <= bound: power_of_y = 1 while power_of_x + power_of_y <= bound: result_set.add(power_of_x + power_of_y) power_of_y *= y # If y=1, this stays 1 forever! power_of_x *= x # If x=1, this stays 1 forever!
Solution: Always check and break when the base is 1:
if y == 1: break # After processing y^0 = 1 if x == 1: break # After processing all y values for x^0 = 1
2. Using List Instead of Set for Duplicates
Another common mistake is using a list and forgetting to handle duplicates, which can occur when different combinations of powers produce the same sum.
Problematic Code:
result = [] # ... loop logic ... result.append(power_of_x + power_of_y) # May add duplicates!
Solution: Use a set to automatically handle duplicates:
result_set = set()
result_set.add(power_of_x + power_of_y) # Automatically handles duplicates
return list(result_set)
3. Incorrect Loop Termination Condition
Using <
instead of <=
in the outer loop condition, which would miss valid powerful integers where x^i = bound
.
Problematic Code:
while power_of_x < bound: # Misses case where x^i + 1 = bound
Solution: Use <=
for the outer loop:
while power_of_x <= bound: # Correctly includes all valid x^i values
4. Not Considering Edge Case of bound < 2
Forgetting that the minimum possible powerful integer is 2 (when x^0 + y^0 = 1 + 1 = 2).
Solution: The current implementation naturally handles this since if bound < 2
, the condition power_of_x + power_of_y <= bound
will be false from the start (1 + 1 = 2 > bound), returning an empty list.
Depth first search is equivalent to which of the tree traversal order?
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!