Taro Logo

Smallest Divisible Digit Product II

#10 Most AskedHard
4 views
Topics:
StringsGreedy AlgorithmsDynamic ProgrammingBit Manipulation

You are given a string num which represents a positive integer, and an integer t.

A number is called zero-free if none of its digits are 0.

Return a string representing the smallest zero-free number greater than or equal to num such that the product of its digits is divisible by t. If no such number exists, return "-1".

Example 1:

Input: num = "1234", t = 256

Output: "1488"

Explanation:

The smallest zero-free number that is greater than 1234 and has the product of its digits divisible by 256 is 1488, with the product of its digits equal to 256.

Example 2:

Input: num = "12355", t = 50

Output: "12355"

Explanation:

12355 is already zero-free and has the product of its digits divisible by 50, with the product of its digits equal to 150.

Example 3:

Input: num = "11111", t = 26

Output: "-1"

Explanation:

No number greater than 11111 has the product of its digits divisible by 26.

Constraints:

  • 2 <= num.length <= 2 * 105
  • num consists only of digits in the range ['0', '9'].
  • num does not contain leading zeros.
  • 1 <= t <= 1014

Solution


Clarifying Questions

When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:

  1. What is the upper bound for the input integer n?
  2. Is n guaranteed to be a positive integer, or should I handle cases where n is zero or negative?
  3. If multiple integers have digits that multiply to n, which one should I return (e.g., the smallest)?
  4. If no such integer exists, is 0 the only acceptable return value, or are there other specific requirements (e.g., throwing an exception)?
  5. Are we concerned about integer overflow when constructing the result, and if so, what should I do in that scenario?

Brute Force Solution

Approach

The goal is to find the smallest number whose digits, when multiplied together, equal a given number. The brute force approach involves checking every possible number, one by one, until we find one that works.

Here's how the algorithm would work step-by-step:

  1. Start with the smallest possible number, which is 1.
  2. Calculate the product of the digits of this number.
  3. See if the product is equal to the given number we are trying to reach.
  4. If it is, we've found a solution!
  5. If not, move on to the next number (2, 3, 4, and so on).
  6. Repeat the process of calculating the digit product and comparing it to the target number for each new number.
  7. If we find multiple numbers that work, keep track of the smallest one.
  8. Continue checking numbers until you either find the smallest possible solution or have checked enough numbers to be reasonably sure a solution doesn't exist.

Code Implementation

def smallest_divisible_digit_product_brute_force(target_number):
    number = 1

    while True:
        product_of_digits = 1
        number_string = str(number)

        # Calculate the product of the digits of the current number.

        for digit_character in number_string:
            digit = int(digit_character)
            product_of_digits *= digit

        # Check if the product of digits matches the target.

        if product_of_digits == target_number:
            return number

        # Increment to the next number.

        number += 1

Big(O) Analysis

Time Complexity
O(10^n)The described brute-force approach iterates through numbers starting from 1 until it finds a number whose digits' product equals the target. In the worst case, if no such number exists or if the smallest such number is very large, the algorithm may need to check all numbers up to a certain limit. The number of iterations is directly related to the magnitude of the number being checked. Since we are effectively checking numbers of up to n digits, where n represents the target product's 'size' in terms of digits needed, and each digit can be 0-9, in the absolute worst case, the algorithm might iterate through numbers up to 10^n, so the time complexity is O(10^n).
Space Complexity
O(1)The provided plain English explanation describes a brute-force approach that iteratively checks numbers starting from 1. It calculates the product of digits for each number. The extra space used includes variables to store the current number being checked and its digit product. Since the number of extra variables is constant and independent of the input 'N' (the target product), the auxiliary space complexity is O(1).

Optimal Solution

Approach

The goal is to find the smallest number whose digits multiply to a given number. Instead of checking every number, we break down the target product into its prime factors (2, 3, 5, 7) and then combine these factors cleverly to create the smallest possible digits.

Here's how the algorithm would work step-by-step:

  1. First, check if the target product is 0 or 1. If it's 0, the answer is 10 if the product itself isn't also 0; if it's 1, the answer is 1.
  2. Next, try to break down the target product by repeatedly dividing it by 9, then 8, then 7, and so on down to 2. Each successful division becomes a digit in our answer.
  3. Store these digits as you find them.
  4. If at any point you can't divide the target product by any number from 9 down to 2, it means the target product has a prime factor larger than 7. This means it's impossible to create the target product with single-digit numbers, so there is no solution.
  5. Finally, if you have a list of digits, sort them in increasing order. This ensures the smallest possible number is created.
  6. Combine the sorted digits to form a single number, which will be the smallest number whose digits multiply to the target product.

Code Implementation

def smallest_divisible_digit_product(target):
    if target == 0:
        return "10"
    if target == 1:
        return "1"

    single_digit_factors = []
    for digit in range(9, 1, -1):
        while target % digit == 0:
            target //= digit
            single_digit_factors.append(digit)

    # If target can't be fully factored by single digits.
    if target > 1:
        return "-1"

    # Sorting digits to form the smallest number.
    single_digit_factors.sort()

    # Construct the smallest possible number.
    smallest_number = "".join(map(str, single_digit_factors))
    return smallest_number

Big(O) Analysis

Time Complexity
O(log n)The algorithm decomposes the input number 'n' by repeatedly dividing it by digits from 9 down to 2. This decomposition process is akin to finding prime factors within a limited range and the number of divisions is bounded by the logarithm of n with a base greater than 1. The sorting of the digits takes time at most proportional to the number of digits, which is log n. Therefore, the dominant factor is the factorization process, leading to a time complexity of O(log n).
Space Complexity
O(log N)The algorithm uses a list to store the digits found during the prime factorization of the input number N. In the worst-case scenario, N can be broken down into several small digits (e.g., if N is a power of 2 or 3), resulting in a number of digits proportional to log N. Sorting this list of digits also requires additional space, but this sorting can be done in-place or using an algorithm with space complexity proportional to the number of digits. Therefore, the overall auxiliary space complexity is O(log N).

Edge Cases

Input n is 0
How to Handle:
Return 10 since 1*0 = 0 is not allowed per prompt definition, but zero is only reachable via digits that result in 10 (special case).
Input n is 1
How to Handle:
Return 1, as the product of the single digit 1 is 1.
Input n is a prime number greater than 9
How to Handle:
Return 0, since no single-digit numbers multiply to a prime greater than 9.
Input n is a large number whose smallest divisible digit product is a very long number, exceeding integer limits
How to Handle:
Use a string or a list of digits to represent the result to avoid integer overflow.
Input n is a relatively large composite number with many possible factorizations
How to Handle:
Optimize the factorization approach to find the smallest possible combination of digits efficiently.
Input is negative
How to Handle:
Since the problem statement specifies a positive integer n, reject negative inputs and return 0.
Input n = 2147483647 (maximum integer value)
How to Handle:
Handle appropriately - the algorithm should correctly factor the number and return the smallest representation or 0 if no such number exists without causing integer overflow in intermediate calculations.
Input results in a very long string due to repeated factors of small digits like 2, 3
How to Handle:
Ensure the string manipulation or digit list construction is memory efficient and doesn't result in memory exhaustion for extreme cases.
0/134 completed