Taro Logo

Check if Number is a Sum of Powers of Three

Medium
Google logo
Google
1 view
Topics:
Bit ManipulationRecursion

Given an integer n, return true if it is possible to represent n as the sum of distinct powers of three. Otherwise, return false.

An integer y is a power of three if there exists an integer x such that y == 3^x.

Examples:

  1. Input: n = 12 Output: true Explanation: 12 = 3^1 + 3^2

  2. Input: n = 91 Output: true Explanation: 91 = 3^0 + 3^2 + 3^4

  3. Input: n = 21 Output: false

Constraints:

  • 1 <= n <= 10^7

Can you provide an efficient algorithm to solve this problem, considering both time and space complexity? Also, think about edge cases such as n = 1, n = 2, and n = 3.

Solution


Naive Solution

A brute force approach would involve generating all possible sums of distinct powers of three up to a certain limit (since n is capped at 10^7, we can determine the highest power of 3 needed). Then, check if n exists within these sums.

This approach is highly inefficient and impractical due to the exponential number of possible sums.

Optimal Solution

The optimal solution involves converting the given integer n into its base-3 representation. If n can be represented as the sum of distinct powers of three, its base-3 representation will only contain the digits 0 and 1. If any digit is 2, it means that we need two of the same power of three to represent n, which violates the "distinct powers" constraint.

Here's a breakdown of the steps:

  1. Iteratively divide n by 3.
  2. Check the remainder of each division.
    • If the remainder is 2, return false.
    • If the remainder is 0 or 1, continue the process with the quotient.
  3. If the loop completes without finding a remainder of 2, return true.

Edge Cases

  • n = 1: This is a valid case as 1 = 30
  • n = 2: This is an invalid case as it requires two 30, which are not distinct
  • n = 3: Valid as 31
  • n = 4: Invalid as it would need one 31 and one 30 + 30

Code

class Solution {
    public boolean checkIfTwoSum(int[] nums, int target) {
        HashSet < Integer > set = new HashSet < > ();
        for (int i = 0; i < nums.length; i++) {
            int complement = target - nums[i];
            if (set.contains(complement)) {
                return true;
            }
            set.add(nums[i]);
        }

        return false;
    }

    public boolean checkDistinctSum(int[] nums, int target) {

        for (int i = 0; i < nums.length; i++) {
            HashSet < Integer > set = new HashSet < > ();
            int complement = target - nums[i];

        }

        return false;
    }
    public boolean checkDistinctSum(int[] nums, int target) {
        if (nums == null || nums.length == 0) {
            return false;
        }

        // Sort the array to use two-pointer approach efficiently
        Arrays.sort(nums);

        int left = 0;
        int right = nums.length - 1;

        while (left < right) {
            int sum = nums[left] + nums[right];

            if (sum == target) {
                // Found a pair with the desired sum
                return true;
            } else if (sum < target) {
                // Sum is too small, move the left pointer to increase the sum
                left++;
            } else {
                // Sum is too large, move the right pointer to decrease the sum
                right--;
            }
        }

        // No pair found with the desired sum
        return false;
    }

    public boolean checkDistinctSum(int[] nums, int target) {
        if (nums == null || nums.length == 0) {
            return false;
        }

        for (int i = 0; i < nums.length - 1; i++) {
            for (int j = i + 1; j < nums.length; j++) {
                if (nums[i] + nums[j] == target) {
                    return true;
                }
            }
        }

        return false;
    }


    public boolean checkDistinctSum(int[] nums, int target) {
        if (nums == null || nums.length < 2) {
            return false; // Need at least two numbers to form a sum
        }

        Set<Integer> seen = new HashSet<>();
        for (int num : nums) {
            int complement = target - num;
            if (seen.contains(complement)) {
                return true; // Found distinct numbers that sum to target
            }
            seen.add(num); // Add current number to the set
        }

        return false; // No distinct numbers found that sum to target
    }
    public boolean checkIfTwoSum(int[] nums, int target) {
        HashSet < Integer > set = new HashSet < > ();
        for (int i = 0; i < nums.length; i++) {
            int complement = target - nums[i];
            if (set.contains(complement)) {
                return true;
            }
            set.add(nums[i]);
        }

        return false;
    }
    public boolean checkIfSumOfPowersOfThree(int n) {
        while (n > 0) {
            if (n % 3 == 2) {
                return false;
            }
            n /= 3;
        }
        return true;
    }
}

Complexity Analysis

  • Time Complexity: O(log3(n)), because in each iteration, n is divided by 3. The number of iterations is proportional to the base-3 logarithm of n.
  • Space Complexity: O(1), because the algorithm uses only a constant amount of extra space.