Open In App

Minimize Range of the Array

Last Updated : 31 Jan, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

Given an array A of size N. In one operation, you can select any number from the array and reduce it to a divisor greater than 1. For example, you can reduce 16 to 2, 4, 8 or 16. You need to find the minimum range of the array by doing any number of operations on the array. You can do multiple operations on a single element as well. The range of the array is defined as the difference between the maximum element and minimum element of the array.

Examples:

Input: N=3 , A=[2 4 8]
Output: 0
Explanation: We can convert the array into [2, 2, 2]. So the difference between the maximum element and minimum element is zero.

Input: N=3 ,A=[3 8 9]
Output:1
Explanation: We can convert the array into [3, 2, 3]. So the difference between the maximum element and minimum element is one.

Approach: We can solve this problem using the below idea

The first observation is that the duplicate elements does not add any thing to the result. for Example [2, 4, 8, 8] in this example if the first 8 is reduce to 2 likewise the other 8 can also be reduced to 2. The main aim of the problem is to minimize the difference between maximum and minimum element of the array. So in order to minimize the difference, we have two options one is to maximize the minimum element of the array or minimize the maximum element of the array. Lets concentrate on maximize the minimum element of the array. Consider an example of [2, 4, 8]. Listing out the factors ( > 1) of these numbers:
Indexes = [0, 1, 2]
2 = [2]
4 = [2, 4]
8 = [2, 4, 8]

We will keep pick up the minimum element from all of the factors of a particular number and push them into a heap. And will keep track of maximum element in the maximum variable. We will pop the smallest element from the heap now difference the smallest element and maximum element that we have kept track of can be the answer. But if there is another factor for the element we have popped we push the factor into the heap again by doing so we can increase the minimum element of the array. We will continue doing the same procedure until the heap becomes empty. And will return minimum of the all those.

Steps to Solve this problem:

  1. Find all the factors in the range [2, 104] using sieve.
  2. Remove all duplicates elements in the array A. By inserting them into a set.
  3. Initialize a variable maximum to zero. To keep track of the maximum element.
  4. Initialize a vector startIndexes which will hold the current index of the factor for a particular element in the array.
  5. Now iterate over the unique sorted elements. Push all the minimum factor for all the elements in the array into a min heap and store maximum of them in variable maximum.
  6. Initialize a variable ans which will store the final result to difference of maximum and top element in the min heap.
  7. If the minimum element having some more factors, we move ahead to the next factor in the list. We will pop the top element from the priority queue and add the next factor and according the increment the startIndexes array.
  8. Continue this procedure until the priority queue becomes empty or there are no more factors exists for top most element.
  9. Return the final result.

Below is the Implementation of the above approach:

C++




#include <bits/stdc++.h>
using namespace std;
 
const int NUM = 10e4 + 1;
vector<int> factors[NUM];
 
// function to find the all factors in the range [2, NUM]
void getFactors()
{
    for (int i = 2; i < NUM; i++) {
        for (int j = i; j < NUM; j += i) {
            factors[j].push_back(i);
        }
    }
}
 
//  function to find the final answer
int findMinimumRange(int N, vector<int>& A)
{
 
    // get factors of all the numbers in the range [2, NUM]
    getFactors();
 
    // to remove duplicates
    set<int> s(A.begin(), A.end());
 
    // assign it to vector uniSorted (unique and sorted
    // elements)
    vector<int> uniSorted(s.begin(), s.end());
 
    N = uniSorted.size();
 
    // Min Heap to hold {factor, index}
    // where factor represents the present factor of the
    // element uniSorted[index]
    priority_queue<pair<int, int>, vector<pair<int, int>>,
                   greater<pair<int, int>>>
        pq;
 
    // to keep track of the maximum element
    int maximum = 0;
 
    // to keep track of the indexes of the factors.
    vector<int> startIndexes(N + 1, 0);
 
    for (int i = 0; i < N; i++) {
        pq.push({ factors[uniSorted[i]][0], i });
        maximum = max(maximum, factors[uniSorted[i]][0]);
    }
 
    // difference between the maximum and minimum element at
    // this point.
    int ans = maximum - pq.top().first;
 
    while (!pq.empty()) {
        int ind = pq.top().second;
        pq.pop();
 
        // break if no more factors are available at index
        // ind
        if (startIndexes[ind] + 1
            == factors[uniSorted[ind]].size())
            break;
 
        // move on to the next index and mark it on
        // startIndexes
        startIndexes[ind] += 1;
 
        pq.push(
            { factors[uniSorted[ind]][startIndexes[ind]],
              ind });
        maximum = max(
            maximum,
            factors[uniSorted[ind]][startIndexes[ind]]);
        ans = min(ans, maximum - pq.top().first);
    }
 
    // return the result
    return ans;
}
 
int main()
{
    int N = 3;
    vector<int> A = { 3, 9, 8 };
    // function call
    cout << findMinimumRange(N, A);
}


Java




import java.util.*;
 
public class Solution {
 
    static final int NUM = 100001; // Constants are similar, but Java arrays start at 0 by default
    static List<Integer>[] factors = new ArrayList[NUM];
 
    // function to find all factors in the range [2, NUM]
    static void getFactors() {
        for (int i = 2; i < NUM; i++) {
            for (int j = i; j < NUM; j += i) {
                if (factors[j] == null) {
                    factors[j] = new ArrayList<>();
                }
                factors[j].add(i);
            }
        }
    }
 
    // function to find the final answer
    static int findMinimumRange(int N, List<Integer> A) {
 
        // get factors of all the numbers in the range [2, NUM]
        getFactors();
 
        // to remove duplicates
        Set<Integer> s = new HashSet<>(A);
 
        // assign it to list uniSorted (unique and sorted elements)
        List<Integer> uniSorted = new ArrayList<>(s);
 
        N = uniSorted.size();
 
        // Min Heap to hold {factor, index}
        // where factor represents the present factor of the
        // element uniSorted[index]
        PriorityQueue<Pair<Integer, Integer>> pq = new PriorityQueue<>(
                Comparator.comparingInt(o -> o.first));
 
        // to keep track of the maximum element
        int maximum = 0;
 
        // to keep track of the indexes of the factors.
        int[] startIndexes = new int[N + 1];
 
        for (int i = 0; i < N; i++) {
            pq.add(new Pair<>(factors[uniSorted.get(i)].get(0), i));
            maximum = Math.max(maximum, factors[uniSorted.get(i)].get(0));
        }
 
        // difference between the maximum and minimum element at this point.
        int ans = maximum - pq.peek().first;
 
        while (!pq.isEmpty()) {
            Pair<Integer, Integer> pair = pq.poll();
            int ind = pair.second;
 
            // break if no more factors are available at index ind
            if (startIndexes[ind] + 1 == factors[uniSorted.get(ind)].size()) {
                break;
            }
 
            // move on to the next index and mark it on startIndexes
            startIndexes[ind] += 1;
 
            pq.add(new Pair<>(factors[uniSorted.get(ind)].get(startIndexes[ind]), ind));
            maximum = Math.max(maximum, factors[uniSorted.get(ind)].get(startIndexes[ind]));
            ans = Math.min(ans, maximum - pq.peek().first);
        }
 
        // return the result
        return ans;
    }
 
    public static void main(String[] args) {
        int N = 3;
        List<Integer> A = Arrays.asList(3, 9, 8);
        // function call
        System.out.println(findMinimumRange(N, A));
    }
 
    // Simple Pair class to hold two values
    static class Pair<T, U> {
        T first;
        U second;
 
        Pair(T first, U second) {
            this.first = first;
            this.second = second;
        }
    }
}
 
 
 
// This code is contributed by akshitaguprzj3


Python3




# Python Implmentation
import heapq
 
NUM = 10**4 + 1
factors = [[] for _ in range(NUM)]
 
# function to find all factors in the range [2, NUM]
def get_factors():
    for i in range(2, NUM):
        for j in range(i, NUM, i):
            factors[j].append(i)
 
# function to find the final answer
def find_minimum_range(N, A):
    # get factors of all numbers in the range [2, NUM]
    get_factors()
 
    # remove duplicates
    s = set(A)
 
    # assign it to a list uni_sorted (unique and sorted elements)
    uni_sorted = sorted(list(s))
 
    N = len(uni_sorted)
 
    # Min Heap to hold (factor, index) where factor represents the present factor
    # of the element uni_sorted[index]
    pq = []
 
    # to keep track of the maximum element
    maximum = 0
 
    # to keep track of the indexes of the factors
    start_indexes = [0] * (N + 1)
 
    for i in range(N):
        heapq.heappush(pq, (factors[uni_sorted[i]][0], i))
        maximum = max(maximum, factors[uni_sorted[i]][0])
 
    # difference between the maximum and minimum element at this point
    ans = maximum - pq[0][0]
 
    while pq:
        factor, ind = heapq.heappop(pq)
 
        # break if no more factors are available at index ind
        if start_indexes[ind] + 1 == len(factors[uni_sorted[ind]]):
            break
 
        # move on to the next index and mark it on start_indexes
        start_indexes[ind] += 1
 
        heapq.heappush(pq, (factors[uni_sorted[ind]][start_indexes[ind]], ind))
        maximum = max(maximum, factors[uni_sorted[ind]][start_indexes[ind]])
        ans = min(ans, maximum - pq[0][0])
 
    # return the result
    return ans
 
if __name__ == "__main__":
    N = 3
    A = [3, 9, 8]
    # function call
    print(find_minimum_range(N, A))
 
# This code is contributed by Tapesh(tapeshdua420)


C#




using System;
using System.Collections.Generic;
 
public class Program
{
    const int NUM = 100001;
    static List<int>[] factors = new List<int>[NUM];
 
    // Function to find all factors in the range [2, NUM]
    public static void GetFactors()
    {
        for (int i = 0; i < NUM; i++)
        {
            factors[i] = new List<int>();
        }
         
        for (int i = 2; i < NUM; i++)
        {
            for (int j = i; j < NUM; j += i)
            {
                factors[j].Add(i);
            }
        }
    }
 
    // Function to find the final answer
    public static int FindMinimumRange(int N, List<int> A)
    {
        // Get factors of all the numbers in the range [2, NUM]
        GetFactors();
 
        // Remove duplicates
        HashSet<int> s = new HashSet<int>(A);
 
        // Assign it to a list uniSorted (unique and sorted elements)
        List<int> uniSorted = new List<int>(s);
        N = uniSorted.Count;
 
        // Min Heap to hold {factor, index}
        SortedSet<Tuple<int, int>> pq = new SortedSet<Tuple<int, int>>();
 
        // To keep track of the maximum element
        int maximum = 0;
 
        // To keep track of the indexes of the factors
        int[] startIndexes = new int[N + 1];
 
        for (int i = 0; i < N; i++)
        {
            pq.Add(Tuple.Create(factors[uniSorted[i]][0], i));
            maximum = Math.Max(maximum, factors[uniSorted[i]][0]);
        }
 
        // Difference between the maximum and minimum element at this point
        int ans = maximum - pq.Min.Item1;
 
        while (pq.Count > 0)
        {
            var tuple = pq.Min;
            pq.Remove(tuple);
 
            int ind = tuple.Item2;
 
            // Break if no more factors are available at index ind
            if (startIndexes[ind] + 1 == factors[uniSorted[ind]].Count)
                break;
 
            // Move on to the next index and mark it on startIndexes
            startIndexes[ind] += 1;
 
            pq.Add(Tuple.Create(factors[uniSorted[ind]][startIndexes[ind]], ind));
            maximum = Math.Max(maximum, factors[uniSorted[ind]][startIndexes[ind]]);
            ans = Math.Min(ans, maximum - pq.Min.Item1);
        }
 
        // Return the result
        return ans;
    }
 
    public static void Main()
    {
        int N = 3;
        List<int> A = new List<int> { 3, 9, 8 };
        // Function call
        Console.WriteLine(FindMinimumRange(N, A));
    }
}
 
 
// This code is contributed by AKSHITAGUPRZJ3


Javascript




const NUM = 10e4 + 1;
const factors = Array.from({ length: NUM }, () => []);
 
// Function to find all factors in the range [2, NUM]
function getFactors() {
    for (let i = 2; i < NUM; i++) {
        for (let j = i; j < NUM; j += i) {
            factors[j].push(i);
        }
    }
}
 
// Function to find the final answer
function findMinimumRange(N, A) {
    // Get factors of all the numbers in the range [2, NUM]
    getFactors();
 
    // Remove duplicates
    const s = new Set(A);
 
    // Assign unique and sorted elements to the array uniSorted
    const uniSorted = Array.from(s).sort((a, b) => a - b);
    N = uniSorted.length;
 
    // Min Heap to hold {factor, index}
    // where factor represents the present factor of the
    // element uniSorted[index]
    const pq = new PriorityQueue((a, b) => a[0] - b[0]);
 
    // To keep track of the maximum element
    let maximum = 0;
 
    // To keep track of the indexes of the factors.
    const startIndexes = new Array(N + 1).fill(0);
 
    for (let i = 0; i < N; i++) {
        pq.enqueue([factors[uniSorted[i]][0], i]);
        maximum = Math.max(maximum, factors[uniSorted[i]][0]);
    }
 
    // Difference between the maximum and minimum element at this point.
    let ans = maximum - pq.peek()[0];
 
    while (!pq.isEmpty()) {
        const [ind, index] = pq.dequeue();
 
        // Break if no more factors are available at index ind
        if (startIndexes[index] + 1 === factors[uniSorted[index]].length) {
            break;
        }
 
        // Move on to the next index and mark it on startIndexes
        startIndexes[index] += 1;
 
        pq.enqueue([factors[uniSorted[index]][startIndexes[index]], index]);
        maximum = Math.max(maximum, factors[uniSorted[index]][startIndexes[index]]);
        ans = Math.min(ans, maximum - pq.peek()[0]);
    }
 
    // Return the result
    return ans;
}
 
// Priority Queue implementation
class PriorityQueue {
    constructor(compare) {
        this.heap = [];
        this.compare = compare;
    }
 
    enqueue(value) {
        this.heap.push(value);
        this.bubbleUp();
    }
 
    dequeue() {
        const root = this.heap[0];
        const last = this.heap.pop();
        if (this.heap.length > 0) {
            this.heap[0] = last;
            this.bubbleDown();
        }
        return root;
    }
 
    peek() {
        return this.heap[0];
    }
 
    isEmpty() {
        return this.heap.length === 0;
    }
 
    bubbleUp() {
        let index = this.heap.length - 1;
        while (index > 0) {
            const parentIndex = Math.floor((index - 1) / 2);
            if (this.compare(this.heap[index], this.heap[parentIndex]) < 0) {
                this.swap(index, parentIndex);
                index = parentIndex;
            } else {
                break;
            }
        }
    }
 
    bubbleDown() {
        let index = 0;
        while (true) {
            const leftChildIndex = 2 * index + 1;
            const rightChildIndex = 2 * index + 2;
            let smallestChildIndex = index;
 
            if (leftChildIndex < this.heap.length &&
                this.compare(this.heap[leftChildIndex], this.heap[smallestChildIndex]) < 0) {
                smallestChildIndex = leftChildIndex;
            }
 
            if (rightChildIndex < this.heap.length &&
                this.compare(this.heap[rightChildIndex], this.heap[smallestChildIndex]) < 0) {
                smallestChildIndex = rightChildIndex;
            }
 
            if (smallestChildIndex !== index) {
                this.swap(index, smallestChildIndex);
                index = smallestChildIndex;
            } else {
                break;
            }
        }
    }
 
    swap(i, j) {
        [this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]];
    }
}
 
// Example usage
const N = 3;
const A = [3, 9, 8];
 
// Function call
console.log(findMinimumRange(N, A));


Output

1

Time Complexity: O(NlogN). Where N is the number of elements of the array
Auxiliary space: O(N * sqrt(N)), Where N is the number of elements of the array.



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads