Given start, end, and an array arr of n numbers. At each step, the start is multiplied by any number in the array and then a mod operation with 100000 is done to get the new start.
Find the minimum steps in which the end can be achieved starting from the start. If it is not possible to reach the end, then return -1.
Input: arr = [2, 5, 7], start = 3, end = 30
Output: 2
Explanation:
Step 1: 3*2 = 6 % 100000 = 6
Step 2: 6*5 = 30 % 100000 = 30
Therefore, in minimum 2 multiplications, we reach the end number which is treated as a destination node of a graph here.
Input: arr = [3, 4, 65], start = 7, end = 66175
Output: 4
Explanation:
Step 1: 7*3 = 21 % 100000 = 21
Step 2: 21*3 = 6 % 100000 = 63
Step 3: 63*65 = 4095 % 100000 = 4095
Step 4: 4095*65 = 266175 % 100000 = 66175
Therefore, in minimum 4 multiplications we reach the end number which is treated as a destination node of a graph here.
Input: arr = [3, 4, 65], start = 7, end = 21
Pre Requisite: Shortest path in undirected graph with unit weights
#include <bits/stdc++.h>
using namespace std;
/* Define P as a shorthand for
the pair <int,int> type */
#define P pair <int,int>
class Solution {
public:
/* Function to determine minimum
multiplications to reach end */
int minimumMultiplications(vector<int>& arr,
int start, int end) {
// Base case
if(start == end) return 0;
// Size of array
int n = arr.size();
int mod = 100000; // mod
/* Array to store minimum
steps (distance array) */
vector<int> minSteps(1e5, INT_MAX);
/* Queue to implement
Dijkstra's algorithm */
queue <P> q;
// Mark initial position as 0
minSteps[start] = 0;
// Add the initial node to queue
q.push({0, start});
// Until the queue is empty
while(!q.empty()) {
// Get the element
auto p = q.front();
q.pop();
int steps = p.first; // steps
int val = p.second; // value
// Check for adjacent neighbors
for(int i=0; i < n; i++) {
// Value of neighboring node
int num = (val * arr[i]) % mod;
// If end is reached, return steps taken
if(num == end) return steps+1;
/* Check if the current steps taken is
less than earlier known steps */
if(steps+1 < minSteps[num]) {
// Update the known steps
minSteps[num] = steps+1;
// Insert the pair in queue
q.push({steps+1, num});
}
}
}
/* Return -1 if reaching
end is not possible */
return -1;
}
};
int main() {
int start = 3, end = 30;
vector<int> arr = {2, 5, 7};
/* Creating an instance of
Solution class */
Solution sol;
/* Function call to determine minimum
multiplications to reach end */
int ans = sol.minimumMultiplications(arr, start, end);
// Output
cout << "The minimum multiplications to reach end is: " << ans;
return 0;
}
import java.util.*;
class Solution {
/* Function to determine minimum
multiplications to reach end */
public int minimumMultiplications(int[] arr,
int start, int end) {
// Base case
if (start == end) return 0;
// Size of array
int n = arr.length;
int mod = 100000; // mod
/* Array to store minimum
steps (distance array) */
int[] minSteps = new int[mod];
Arrays.fill(minSteps, Integer.MAX_VALUE);
/* Queue to implement
Dijkstra's algorithm */
Queue<int[]> q = new LinkedList<>();
// Mark initial position as 0
minSteps[start] = 0;
// Add the initial node to queue
q.add(new int[]{0, start});
// Until the queue is empty
while (!q.isEmpty()) {
// Get the element
int[] p = q.poll();
int steps = p[0]; // steps
int val = p[1]; // value
// Check for adjacent neighbors
for (int i = 0; i < n; i++) {
// Value of neighboring node
int num = (val * arr[i]) % mod;
// If end is reached, return steps taken
if (num == end) return steps + 1;
/* Check if the current steps taken is
less than earlier known steps */
if (steps + 1 < minSteps[num]) {
// Update the known steps
minSteps[num] = steps + 1;
// Insert the pair in queue
q.add(new int[]{steps + 1, num});
}
}
}
/* Return -1 if reaching
end is not possible */
return -1;
}
public static void main(String[] args) {
int start = 3, end = 30;
int[] arr = {2, 5, 7};
/* Creating an instance of
Solution class */
Solution sol = new Solution();
/* Function call to determine minimum
multiplications to reach end */
int ans = sol.minimumMultiplications(arr, start, end);
// Output
System.out.println("The minimum multiplications to reach end is: " + ans);
}
}
from collections import deque
class Solution:
# Function to determine minimum
# multiplications to reach end
def minimumMultiplications(self, arr, start, end):
# Base case
if start == end:
return 0
# Size of array
n = len(arr)
mod = 100000 # mod
# Array to store minimum
# steps (distance array)
minSteps = [float('inf')] * 100000
# Queue to implement
# Dijkstra's algorithm
q = deque()
# Mark initial position as 0
minSteps[start] = 0
# Add the initial node to queue
q.append((0, start))
# Until the queue is empty
while q:
# Get the element
steps, val = q.popleft()
# Check for adjacent neighbors
for i in range(n):
# Value of neighboring node
num = (val * arr[i]) % mod
# If end is reached, return steps taken
if num == end:
return steps + 1
# Check if the current steps taken is
# less than earlier known steps
if steps + 1 < minSteps[num]:
# Update the known steps
minSteps[num] = steps + 1
# Insert the pair in queue
q.append((steps + 1, num))
# Return -1 if reaching
# end is not possible
return -1
if __name__ == "__main__":
start = 3
end = 30
arr = [2, 5, 7]
# Creating an instance of
# Solution class
sol = Solution()
# Function call to determine minimum
# multiplications to reach end
ans = sol.minimumMultiplications(arr, start, end)
# Output
print("The minimum multiplications to reach end is:", ans)
class Solution {
/* Function to determine minimum
multiplications to reach end */
minimumMultiplications(arr, start, end) {
// Base case
if (start === end) return 0;
// Size of array
let n = arr.length;
let mod = 100000; // mod
/* Array to store minimum
steps (distance array) */
let minSteps = new Array(100000).fill(Number.MAX_SAFE_INTEGER);
/* Queue to implement
Dijkstra's algorithm */
let q = [];
// Mark initial position as 0
minSteps[start] = 0;
// Add the initial node to queue
q.push([0, start]);
// Until the queue is empty
while (q.length > 0) {
// Get the element
let [steps, val] = q.shift();
// Check for adjacent neighbors
for (let i = 0; i < n; i++) {
// Value of neighboring node
let num = (val * arr[i]) % mod;
// If end is reached, return steps taken
if (num === end) return steps + 1;
/* Check if the current steps taken is
less than earlier known steps */
if (steps + 1 < minSteps[num]) {
// Update the known steps
minSteps[num] = steps + 1;
// Insert the pair in queue
q.push([steps + 1, num]);
}
}
}
/* Return -1 if reaching
end is not possible */
return -1;
}
}
let start = 3, end = 30;
let arr = [2, 5, 7];
/* Creating an instance of
Solution class */
let sol = new Solution();
/* Function call to determine minimum
multiplications to reach end */
let ans = sol.minimumMultiplications(arr, start, end);
// Output
console.log("The minimum multiplications to reach end is:", ans);
Time Complexity: O(100000*N) (where N is the length of given array)
A simple BFS traversal is performed taking O(V+E) time, where V represents nodes (which can be 100000 in the worst case) and E represents the number of edges (transitions) (which can be 100000*N, since for every value, N edges are formed). This makes the overall time complexity as O(100000*N).
Space Complexity: O(100000*N)
Q: Why does BFS work best for this problem?
A: BFS guarantees finding the minimum steps first, as it explores all numbers at step k before moving to step k+1.
Q: Why do we take modulo 100000?
A: The modulo ensures numbers stay bounded within 0-99999, preventing overflow and keeping the graph finite.
Q: What if we allowed division (/ operation) along with multiplication?
A: The graph would contain both multiplication and division edges, requiring careful handling of non-integer results.
Q: Can this be solved using Dynamic Programming?
A: No, because this is a shortest path search problem, not an optimization problem with overlapping subproblems.