Max occurring divisor in an interval


Let x and y be two numbers. In this case, x is said to be a divisor of y if when y is divided by x it returns zero remainder. The maximum occurring divisor in an interval is the number that is a divisor of the maximum number of elements of that interval.

Problem Statement

Given an interval [a, b]. Find the maximum occurring divisor in the range including both a and b, except ‘1’. In case all divisors have equal occurrence, return 1.

Sample Example 1

Input [2, 5]
Output 2

Explanation − Divisors of 2 = {1, 2}, Divisors of 3 = {1, 3}, Divisors of 4 = {1, 2, 4}, Divisors of 5 = {1, 5}. 2 is the most occurring divisor.

Sample Example 2

Input [2, 5]
Output 2

Explanation − Divisors of 2 = {1, 2}, Divisors of 3 = {1, 3}, Divisors of 4 = {1, 2, 4}, Divisors of 5 = {1, 5}. 2 is the most occurring divisor.

Approach 1: Brute Force

The brute force approach to the problem will be to find all the divisors of all the numbers in the interval and store them in a map along with their number of occurrences.

Algorithm

procedure divisors (num)

  • for i = 1 to n1/2+1

  • if num%i == 0

  • if num/i == i

  • if i is not in the map then insert (i, 1)

  • else map[i]++

  • else

  • if i is not in the map then insert (i, 1)

  • else map[i]++

  • if num/i is not in the map then insert (num/i, 1)

  • else map[num/i]++

Procedure maxDivisors (a, b)

  • for n = a to b

  • divisors (n)

  • map.erase(1)

  • divisor = 1, count = int_min

  • for every element in the map it

  • if it.value > count

  • count = it.value

  • divisor = it.key

Example: C++ Implementation

In the following program, we find divisors of each number in the divisors() function and the maximum occurring divisor in the maxdivisor() function.

#include <bits/stdc++.h>
using namespace std;

// map storing occurrence of each divisor
unordered_map<int, int> occ;

// function to find all the divisors of a number and store it in map
void divisors(int num){
   for (int i = 1; i <= (sqrt(num) + 1); i++)    {
   
      // checking if i is divisor of num
      if (num % i == 0)        {
      
         // checking if num has identical divisors i.e. if i*i == num
         // if identical divisors then save only one
         if (num / i == i) {
            if (occ.find(i) == occ.end()) {
               occ.insert(make_pair(i, 1));
            }
            else{
               occ[i]++;
            }
         }
         else{
         
            // saving divisor i
            if (occ.find(i) == occ.end()) {
               occ.insert(make_pair(i, 1));
            }
            else{
               occ[i]++;
            }
            
            // saving the divisor of num corresponding to i
            if (occ.find(num / i) == occ.end()) {
               occ.insert(make_pair(num / i, 1));
            }
            else{
               occ[num / i]++;
            }
         }
      }
   }
}

// function to find maximum occurring divisor in an interval
int maxDivisor(int a, int b){
   for (int n = a; n <= b; n++){
      divisors(n);
   }
   
   // deleting all occurrences of 1 as 1 is not to be returned until the interval is [1,1]
   occ.erase(1);
   
   // divisor set as 1 for edge case scenario when interval is [1,1]
   int div = 1, cnt = INT_MIN;
   for (auto it = occ.begin(); it != occ.end(); it++) {
      if (it->second > cnt) {
         cnt = it->second;
         div = it->first;
      }
   }
   return div;
}
int main(){
   int a = 4, b = 7;
   cout << "For the interval [" << a << ", " << b << "] maximum occurring divisor = ";
   cout << maxDivisor(a, b);
   return 0;
}

Output

For the interval [4, 7] maximum occurring divisor = 2

Time Complexity − O(n3/2) because for every number in the interval, for finding the divisor a loop of complexity O(n1/2) is executed.

Space Complexity − O(n), map space.

Appraoch 2

The above approach can be optimised further by reducing the time to fill the map with the occurrence of each divisor. Rather than finding the divisor of each number, the occurrence of each divisor in the interval can be known by doing computations on the lower and upper bound of the interval.

Let’s take an example of the interval [2, 5].

The possible set of divisors is from 1 to 5. Thus occurrence of 1 = 5/1 - 2/1 +1 = 4. Occurrence of 2 = 5/2 - 2/2 + 1 = 2. Occurrence of 3 = 5/3 - 2/3 = 1. Occurrence of 4 = 5/4 - 2/4 = 1. Occurrence of 5 = 5/5 - 2/5 = 1.

The above can be formalised as,

if lower-bound%divisor == 0 then occ = upper-bound/divisor - lower-bound/divisor + 1

else occ = upper-bound/divisor - lower-bound/divisor

Algorithm

procedure maxDivisor (a, b)

  • for i = 2 to b

  • if a%i == 0

  • times = b/i - a/i +1

  • else

  • times = b/i - a/i

  • map.insert(i, times)

  • divisor = 1, count = int_min

  • for every element in the map it

  • if it.value > count

  • count = it.value

  • divisor = it.key

Example: C++ Implementation

In the following program, rather than finding the divisors of a number we go in the reverse order and for each divisor find how many multiples it has in the interval.

#include <bits/stdc++.h>
using namespace std;

// function to find maximum occurring divisor in an interval
int maxDivisor(int a, int b){

   // map used to store occurrences of divisors
   unordered_map<int, int> occ;
   for (int i = 2; i <= b; i++){
      int times;
      if (a % i == 0){
         times = (b / i) - (a / i) + 1;
      }
      else{
         times = (b / i) - (a / i);
      }
      occ.insert(make_pair(i, times));
   }

   // divisor set as 1 for edge case scenario when interval is [1,1]
   int div = 1, cnt = INT_MIN;
   for (auto it = occ.begin(); it != occ.end(); it++){
      if (it->second > cnt){
         cnt = it->second;
         div = it->first;
      }
   }
   return div;
}
int main(){
   int a = 1, b = 10;
   cout << "For the interval [" << a << ", " << b << "] maximum occurring divisor = ";
   cout << maxDivisor(a, b);
   return 0;
}

Output

For the interval [1, 10] maximum occurring divisor = 2

Approach 3

A very simple solution to the problem is observed as follows,

In any interval with size > 1, half of the numbers (every even number) will have 2 as their divisor.

Thus it can be used as follows.

Algorithm

procedure maxDivisors (a, b)

  • if a == b

  • ans = a

  • else

  • ans = 2

Example: C++ Implementation

In the following program, we implement the observation that every even number has 2 as a divisor.

#include <bits/stdc++.h>
using namespace std;

// function to find the maximum occurring divisor in an interval
int maxDivisor(int a, int b){
   if (a == b){
      return a;
   } else {
      return 2;
   }
}
int main(){
   int a = 1, b = 10;
   cout << "For the interval [" << a << ", " << b << "] maximum occurring divisor = ";
   cout << maxDivisor(a, b);
   return 0;
}

Output

For the interval [1, 10] maximum occurring divisor = 2

Conclusion

In conclusion, in order to find maximum occurring divisor in an interval, we can use the above approaches that range in time from O(n3/2) to O(1) and in space from O(n) to O(1).

Updated on: 25-Jul-2023

94 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements