Smallest subarray with GCD as 1 | Segment Tree

Given an array arr[], the task is to find the smallest sub-arrays with GCD equal to 1. If there is no such sub-array then print -1.

Examples:

Input: arr[] = {2, 6, 3}
Output: 3
{2, 6, 3} is the only sub-array with GCD = 1.

Input: arr[] = {2, 2, 2}
Output: -1

Approach: This problem can be solved in O(NlogN) using segment-tree data structure. The segment that will be built can be used to answer range-gcd queries.



Let’s understand the algorithm now. Use the two-pointer technique to solve this problem. Let’s make a few observations before discussing the algorithm.

After the above observation, two-pointer technique makes perfect sense i.e. if the length
of the smallest R is known for an index L then for an index L + 1, the search needs to be started from R on-wards.

Below is the implementation of the above approach:

filter_none

edit
close

play_arrow

link
brightness_4
code

// C++ implementation of the approach
#include <bits/stdc++.h>
using namespace std;
#define maxLen 30
  
// Array to store segment-tree
int seg[3 * maxLen];
  
// Function to build segment-tree to
// answer range GCD queries
int build(int l, int r, int in, int* arr)
{
    // Base-case
    if (l == r)
        return seg[in] = arr[l];
  
    // Mid element of the range
    int mid = (l + r) / 2;
  
    // Merging the result of left and right sub-tree
    return seg[in] = __gcd(build(l, mid, 2 * in + 1, arr),
                           build(mid + 1, r, 2 * in + 2, arr));
}
  
// Function to perform range GCD queries
int query(int l, int r, int l1, int r1, int in)
{
    // Base-cases
    if (l1 <= l and r <= r1)
        return seg[in];
    if (l > r1 or r < l1)
        return 0;
  
    // Mid-element
    int mid = (l + r) / 2;
  
    // Calling left and right child
    return __gcd(query(l, mid, l1, r1, 2 * in + 1),
                 query(mid + 1, r, l1, r1, 2 * in + 2));
}
  
// Function to find the required length
int findLen(int* arr, int n)
{
    // Building the segment tree
    build(0, n - 1, 0, arr);
  
    // Two pointer variables
    int i = 0, j = 0;
  
    // To store the final answer
    int ans = INT_MAX;
  
    // Looping
    while (i < n) {
  
        // Incrementing j till we don't get
        // a gcd value of 1
        while (j < n and query(0, n - 1, i, j, 0) != 1)
            j++;
  
        if (j == n)
            break;
  
        // Updating the final answer
        ans = min((j - i + 1), ans);
  
        // Incrementing i
        i++;
  
        // Updating j
        j = max(j, i);
    }
  
    // Returning the final answer
    if (ans == INT_MAX)
        return -1;
    else
        return ans;
}
  
// Driver code
int main()
{
    int arr[] = { 2, 2, 2 };
    int n = sizeof(arr) / sizeof(int);
  
    cout << findLen(arr, n);
  
    return 0;
}
chevron_right

filter_none

edit
close

play_arrow

link
brightness_4
code

// Java implementation of the approach
class GFG
{
static int maxLen = 30;
  
// Array to store segment-tree
static int []seg = new int[3 * maxLen];
  
// Function to build segment-tree to
// answer range GCD queries
static int build(int l, int r, 
                 int in, int[] arr)
{
    // Base-case
    if (l == r)
        return seg[in] = arr[l];
  
    // Mid element of the range
    int mid = (l + r) / 2;
  
    // Merging the result of left and right sub-tree
    return seg[in] = __gcd(build(l, mid, 2 * in + 1, arr),
                           build(mid + 1, r, 2 * in + 2, arr));
}
  
// Function to perform range GCD queries
static int query(int l, int r, 
                 int l1, int r1, int in)
{
    // Base-cases
    if (l1 <= l && r <= r1)
        return seg[in];
    if (l > r1 || r < l1)
        return 0;
  
    // Mid-element
    int mid = (l + r) / 2;
  
    // Calling left and right child
    return __gcd(query(l, mid, l1, r1, 2 * in + 1),
                 query(mid + 1, r, l1, r1, 2 * in + 2));
}
  
// Function to find the required length
static int findLen(int []arr, int n)
{
    // Building the segment tree
    build(0, n - 1, 0, arr);
  
    // Two pointer variables
    int i = 0, j = 0;
  
    // To store the final answer
    int ans = Integer.MAX_VALUE;
  
    // Looping
    while (i < n)
    {
  
        // Incrementing j till we don't get
        // a gcd value of 1
        while (j < n && query(0, n - 1
                              i, j, 0) != 1)
            j++;
  
        if (j == n)
            break;
  
        // Updating the final answer
        ans = Math.min((j - i + 1), ans);
  
        // Incrementing i
        i++;
  
        // Updating j
        j = Math.max(j, i);
    }
  
    // Returning the final answer
    if (ans == Integer.MAX_VALUE)
        return -1;
    else
        return ans;
}
  
static int __gcd(int a, int b) 
    return b == 0 ? a : __gcd(b, a % b);     
  
// Driver code
public static void main(String[] args)
{
    int arr[] = { 2, 2, 2 };
    int n = arr.length;
  
    System.out.println(findLen(arr, n));
}
}
  
// This code is contributed by 29AjayKumar
chevron_right

filter_none

edit
close

play_arrow

link
brightness_4
code

# Python3 implementation of the approach
from math import gcd as __gcd
  
maxLen = 30
  
# Array to store segment-tree
seg = [0 for i in range(3 * maxLen)]
  
# Function to build segment-tree to
# answer range GCD queries
def build(l, r, inn, arr):
      
    # Base-case
    if (l == r):
        seg[inn] = arr[l]
        return seg[inn]
  
    # Mid element of the range
    mid = (l + r) // 2
  
    # Merging the result of 
    # left and right sub-tree
    seg[inn] = __gcd(build(l, mid,
                           2 * inn + 1, arr), 
                     build(mid + 1, r, 
                           2 * inn + 2, arr))
  
    return seg[inn]
  
# Function to perform range GCD queries
def query(l, r, l1, r1, inn):
      
    # Base-cases
    if (l1 <= l and r <= r1):
        return seg[inn]
    if (l > r1 or r < l1):
        return 0
  
    # Mid-element
    mid = (l + r) // 2
  
    # Calling left and right child
    x=__gcd(query(l, mid, l1, r1,
                  2 * inn + 1), 
            query(mid + 1, r, l1, r1,
                  2 * inn + 2))
    return x
  
# Function to find the required length
def findLen(arr, n):
      
    # Buildinng the segment tree
    build(0, n - 1, 0, arr)
  
    # Two pointer variables
    i = 0
    j = 0
  
    # To store the finnal answer
    ans = 10**9
  
    # Loopinng
    while (i < n):
  
        # Incrementinng j till we 
        # don't get a gcd value of 1
        while (j < n and query(0, n - 1,
                               i, j, 0) != 1):
            j += 1
  
        if (j == n):
            break;
  
        # Updatinng the finnal answer
        ans = minn((j - i + 1), ans)
  
        # Incrementinng i
        i += 1
  
        # Updatinng j
        j = max(j, i)
  
    # Returninng the finnal answer
    if (ans == 10**9):
        return -1
    else:
        return ans
  
# Driver code
arr = [2, 2, 2]
n = len(arr)
  
print(findLen(arr, n))
  
# This code is contributed by Mohit Kumar
chevron_right

filter_none

edit
close

play_arrow

link
brightness_4
code

// C# implementation of the approach
using System;
  
class GFG
{
    static int maxLen = 30;
      
    // Array to store segment-tree
    static int []seg = new int[3 * maxLen];
      
    // Function to build segment-tree to
    // answer range GCD queries
    static int build(int l, int r, 
                     int ind, int[] arr)
    {
        // Base-case
        if (l == r)
            return seg[ind] = arr[l];
      
        // Mid element of the range
        int mid = (l + r) / 2;
      
        // Merging the result of left and right sub-tree
        return seg[ind] = __gcd(build(l, mid, 2 * ind + 1, arr),
                                build(mid + 1, r, 2 * ind + 2, arr));
    }
      
    // Function to perform range GCD queries
    static int query(int l, int r, 
                     int l1, int r1, int ind)
    {
        // Base-cases
        if (l1 <= l && r <= r1)
            return seg[ind];
        if (l > r1 || r < l1)
            return 0;
      
        // Mid-element
        int mid = (l + r) / 2;
      
        // Calling left and right child
        return __gcd(query(l, mid, l1, r1, 2 * ind + 1),
                     query(mid + 1, r, l1, r1, 2 * ind + 2));
    }
      
    // Function to find the required length
    static int findLen(int []arr, int n)
    {
        // Building the segment tree
        build(0, n - 1, 0, arr);
      
        // Two pointer variables
        int i = 0, j = 0;
      
        // To store the final answer
        int ans = int.MaxValue;
      
        // Looping
        while (i < n)
        {
      
            // Incrementing j till we don't get
            // a gcd value of 1
            while (j < n && query(0, n - 1, 
                                  i, j, 0) != 1)
                j++;
      
            if (j == n)
                break;
      
            // Updating the final answer
            ans = Math.Min((j - i + 1), ans);
      
            // Incrementing i
            i++;
      
            // Updating j
            j = Math.Max(j, i);
        }
      
        // Returning the final answer
        if (ans == int.MaxValue)
            return -1;
        else
            return ans;
    }
      
    static int __gcd(int a, int b) 
    
        return b == 0 ? a : __gcd(b, a % b);     
    
      
    // Driver code
    public static void Main()
    {
        int []arr = { 2, 2, 2 };
        int n = arr.Length;
      
        Console.WriteLine(findLen(arr, n));
    }
}
  
// This code is contributed by kanugargng
chevron_right

Output:
-1

Attention reader! Don’t stop learning now. Get hold of all the important DSA concepts with the DSA Self Paced Course at a student-friendly price and become industry ready.





Check out this Author's contributed articles.

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 Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.



Article Tags :