Facebook Pixel

970. Powerful Integers

MediumHash TableMathEnumeration
Leetcode Link

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 and y are given integers
  • i and j are non-negative integers (i.e., i ≥ 0 and j ≥ 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.

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

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 it a)
  • The inner loop generates all possible values of y^j (let's call it b)
  • For each combination, if a + b ≤ bound, then a + 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:

  1. Initialize a set to store all powerful integers found. Using a set automatically handles duplicate values.

  2. Outer loop for powers of x:

    • Start with a = 1 (which represents x^0)
    • Continue while a ≤ bound (since a + b must be ≤ bound, and minimum b is 1)
    • After each iteration, multiply a by x to get the next power
  3. Inner loop for powers of y:

    • For each value of a, start with b = 1 (which represents y^0)
    • Continue while a + b ≤ bound
    • Add a + b to the set as it's a valid powerful integer
    • After each iteration, multiply b by y to get the next power
  4. Handle special cases:

    • If y = 1, break the inner loop after the first iteration since y^j will always equal 1
    • If x = 1, break the outer loop after completing all inner iterations since x^i will always equal 1
  5. 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 to bound
  • b takes values: 1, y, y^2, y^3, ... up to the largest power where a + 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 Evaluator

Example 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

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

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

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

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. Since a starts at 1 and multiplies by x each iteration (when x > 1), it runs at most log_x(bound) times. When x = 1, it runs only once due to the break statement.
  • The inner loop iterates while a + b ≤ bound. Since b starts at 1 and multiplies by y each iteration (when y > 1), it runs at most log_y(bound) times. When y = 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.

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

Depth first search is equivalent to which of the tree traversal order?


Recommended Readings

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

Load More