We use cookies (including Google cookies) to personalize ads and analyze traffic. By continuing to use our site, you accept our Privacy Policy.

Digit Operations to Make Two Integers Equal

Number: 3655

Difficulty: Medium

Paid? No

Companies: N/A


Problem Description

Given two integers n and m having the same number of digits, you may change any one digit of n at a time by either increasing it by 1 (if it is not 9) or decreasing it by 1 (if it is not 0). However, at every step (including the original n and at every intermediate result) the current integer must not be a prime number. The goal is to convert n to m with a sequence of these digit operations such that the transformation cost––which is defined as the sum of all the integer values that n takes (including the starting value and after each operation)––is minimized. Return the minimum cost if possible, otherwise return -1.


Key Insights

  • Model the problem as a weighted graph with nodes representing valid integers (with the given number of digits and not prime) and edges representing a single allowed digit operation.
  • The weight of an edge from one integer to its neighbor is the neighbor’s integer value (and the starting integer is also charged).
  • Use Dijkstra’s algorithm in order to find the minimum cost path from n to m.
  • Pre-compute all primes up to 10^4 (the maximum possible value) so that each generated neighbor can be quickly validated.
  • Ensure that digit operations do not produce numbers with a different number of digits (avoid producing a leading zero).

Space and Time Complexity

Time Complexity: O(N * D) where N is the number of states (roughly up to 9 * 10^(d-1) for numbers with d digits, d ≤ 4) and D is the number of digits. This is acceptable given the constraints. Space Complexity: O(N) for storing the cost for each valid state and the prime-check table.


Solution

We use Dijkstra’s algorithm to traverse the state space where each state is a valid integer with the same number of digits as n. Each transition changes one digit by ±1 (ensuring that the most significant digit never becomes 0 and that intermediate states are not prime). The cost accumulated when moving to a neighbor equals the neighbor’s value. The algorithm proceeds by:

  1. Precomputing a sieve to mark prime numbers up to 10^4.
  2. Checking that the starting integer (n) and target integer (m) are non-prime.
  3. Converting the current integer to a string representation so that we can perform digit-level operations.
  4. For each valid digit operation (increase if digit < 9, decrease if digit > 0 and if it doesn’t result in a leading zero), computing the new integer value and validating that it is non-prime.
  5. Using a min-heap (priority queue) to always expand the state with the lowest total cost path so far.
  6. If m is reached, return the total cost; otherwise, if no valid transformation exists, return -1.

Code Solutions

import heapq

def is_prime_sieve(limit):
    sieve = [True] * (limit+1)
    sieve[0] = sieve[1] = False
    for i in range(2, int(limit**0.5)+1):
        if sieve[i]:
            for j in range(i*i, limit+1, i):
                sieve[j] = False
    return sieve

def minCostTransformation(n, m):
    # Determine number of digits and bounds
    str_n = str(n)
    digits = len(str_n)
    low_bound = 10**(digits-1)
    high_bound = 10**digits - 1
    
    # Pre-compute prime information for numbers up to high_bound (or 10^4)
    sieve = is_prime_sieve(10000)
    
    # If n or m is prime, transformation is invalid
    if sieve[n] or sieve[m]:
        return -1
    
    # Dijkstra: each state is (cost, value)
    heap = [(n, n)]  # (current total cost, current value)
    # Use dictionary to store the minimum cost to reach state.
    best = {n: n}
    
    while heap:
        cost, cur = heapq.heappop(heap)
        # Check if we reached target state m
        if cur == m:
            return cost
        # If we already found a cheaper path, skip processing this state.
        if cost > best.get(cur, float('inf')):
            continue
        cur_str = str(cur)
        # Explore all neighbors by adjusting each digit by ±1
        for i in range(digits):
            digit = int(cur_str[i])
            for d in (-1, 1):
                new_digit = digit + d
                # Check digit constraints: within [0,9]
                if new_digit < 0 or new_digit > 9:
                    continue
                # For the most significant digit, ensure it is not 0
                if i == 0 and new_digit == 0:
                    continue
                # Create new number string with one digit modified
                new_num_str = cur_str[:i] + str(new_digit) + cur_str[i+1:]
                new_num = int(new_num_str)
                # Must have same number of digits and be non-prime
                if new_num < low_bound or new_num > high_bound or sieve[new_num]:
                    continue
                new_cost = cost + new_num
                if new_cost < best.get(new_num, float('inf')):
                    best[new_num] = new_cost
                    heapq.heappush(heap, (new_cost, new_num))
    return -1

# Example usage:
print(minCostTransformation(10, 12))  # Expected output: 85
print(minCostTransformation(4,8))     # Expected output: -1
print(minCostTransformation(6,2))     # Expected output: -1
← Back to All Questions