Nearest element with at-least one common prime factor

Given an array arr[], find nearest element for every element such that there is at least one common prime factor. In output, we need to print position of closest element.

Input: arr[] = {2, 9, 4, 3, 13}
Output: 3 4 1 2 -1
Explanation : 
Closest element for 1st element is 3rd. 
=>Common prime factor of 1st and 3rd elements
  is 2.
Closest element for 2nd element is 4th.
=>Common prime factor of 2nd and 4th elements
  is 3.

Naive approach

Common prime factor will only exist if GCD of these two numbers will greater than 1. Simple brute force is to run the two loops one inside the another and iterate one by one from each index to both the sides simultaneously and find the gcd which is greater than 1. Whenever we found the answer then just break the loop and the print. If we reached the end of array after traversing both the sides then simply print -1.

// C++ program to print nearest element with at least
// one common prime factor.
#include<bits/stdc++.h>
using namespace std;

void nearestGcd(int arr[], int n)
{
    // Loop covers the every element of arr[]
    for (int i=0; i<n; ++i)
    {
        int closest = -1;

        // Loop that covers from 0 to i-1 and i+1
        // to n-1 indexes simultaneously
        for (int j=i-1, k=i+1; j>0 || k<=n; --j, ++k)
        {
            if (j>=0 && __gcd(arr[i], arr[j]) > 1)
            {
                closest = j+1;
                break;
            }
            if (k<n && __gcd(arr[i], arr[k])>1)
            {
                closest = k+1;
                break;
            }
        }

        // print position of closest element
        cout << closest << " ";
    }
}

// Drive code
int main()
{
    int arr[] = {2, 9, 4, 3, 13};
    int n = sizeof(arr)/sizeof(arr[0]);
    nearestGcd(arr, n);
    return 0;
}
Output: 3 4 1 2 -1

Time complexity: O(n2)
Auxiliary space: O(1)

Efficient Approach

We find prime factors of all array elements. To quickly find prime factors, we use Sieve of Eratosthenes. For every element, we consider all prime factors and keep track of closest element with common factor.

// C++ program to print nearest element with at least
// one common prime factor.
#include <bits/stdc++.h>
using namespace std;

const int MAX = 100001;
const int INF = INT_MAX;

int primedivisor[MAX], dist[MAX], pos[MAX], divInd[MAX];

vector<int> divisors[MAX];

// Pre-computation of smallest prime divisor
// of all numbers
void sieveOfEratosthenes()
{
    for (int i=2; i*i < MAX; ++i)
    {
        if (!primedivisor[i])
            for (int j = i*i; j < MAX; j += i)
                primedivisor[j] = i;
    }

    // Prime number will have same divisor
    for (int i = 1; i < MAX; ++i)
        if (!primedivisor[i])
            primedivisor[i] = i;
}

// Function to calculate all divisors of
// input array
void findDivisors(int arr[], int n)
{
    for (int i=0; i<MAX; ++i)
        pos[i] = divInd[i] = -1, dist[i] = INF;

    for (int i=0; i<n; ++i)
    {
        int num = arr[i];
        while (num > 1)
        {
            int div = primedivisor[num];
            divisors[i].push_back(div);
            while (num % div == 0)
                num /= div;
        }
    }
}

void nearestGCD(int arr[], int n)
{
    // Pre-compute all the divisors of array
    // element by using prime factors
    findDivisors(arr, n);

    // Traverse all elements,
    for (int i=0; i<n; ++i)
    {
        // For every divisor of current element,
        // find closest element.
        for (auto &div: divisors[i])
        {
            // Visit divisor if not visited
            if (divInd[div] == -1)
                divInd[div] = i;
            else
            {
                // Fetch the index of visited divisor
                int ind = divInd[div];

                // Update the divisor index to current index
                divInd[div] = i;

                // Set the minimum distance
                if (dist[i] > abs(ind-i))
                {
                    // Set the min distance of current
                    // index 'i' to nearest one
                    dist[i] = abs(ind-i);

                    // Add 1 as indexing starts from 0
                    pos[i] = ind + 1;
                }

                if (dist[ind] > abs(ind-i))
                {
                    // Set the min distance of found index 'ind'
                    dist[ind] = abs(ind-i);

                    // Add 1 as indexing starts from 0
                    pos[ind] = i + 1;
                }
            }
        }
    }
}

// Driver code
int main()
{
    // Simple sieve to find smallest prime
    // divisor of number from 2 to MAX
    sieveOfEratosthenes();

    int arr[] = {2, 9, 4, 3, 13};
    int n = sizeof(arr)/sizeof(arr[0]);

    // function to calculate nearest distance
    // of every array elements
    nearestGCD(arr, n);

    // Print the nearest distance having GDC>1
    for (int i=0; i<n; ++i)
        cout << pos[i] << " ";
    return 0;
}
Output: 
3 4 1 2 -1

Time complexity: O(MAX * log(log (MAX) ) )
Auxiliary space: O(MAX)

This article is contributed by Shubham Bansal. If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above

GATE CS Corner    Company Wise Coding Practice





Writing code in comment? Please use code.geeksforgeeks.org, generate link and share the link here.