Dada una array arr[] de n números y un entero k, encuentre la longitud de la sub-array mínima con gcd igual a k.
Ejemplo:
Input: arr[] = {6, 9, 7, 10, 12, 24, 36, 27}, K = 3 Output: 2 Explanation: GCD of subarray {6,9} is 3. GCD of subarray {24,36,27} is also 3, but {6,9} is the smallest
Nota: El análisis de la complejidad del tiempo de los enfoques siguientes supone que los números tienen un tamaño fijo y encontrar el GCD de dos elementos lleva un tiempo constante.
Encuentre GCD de todos los subarreglos y realice un seguimiento del subarreglo de longitud mínima con gcd k. La complejidad temporal de esto es O(n 3 ), O(n 2 ) para cada subarreglo y O(n) para encontrar gcd de un subarreglo.
Método 2
Encuentre el GCD de todos los subarreglos usando el enfoque basado en el árbol de segmentos discutido aquí . La complejidad temporal de esta solución es O(n 2 logn), O(n 2 ) para cada subarreglo y O(logn) para encontrar el GCD del subarreglo usando un árbol de segmentos.
Método 3
La idea es utilizar el árbol de segmentos y la búsqueda binaria para lograr la complejidad de tiempo O(n (logn) 2 ).
- Si tenemos cualquier número igual a ‘k’ en la array, la respuesta es 1, ya que MCD de k es k. Regreso 1.
- Si no hay ningún número que sea divisible por k, entonces MCD no existe. Devuelve -1.
- Si ninguno de los casos anteriores es cierto, la longitud del subarreglo mínimo es mayor que 1 o GCD no existe. En este caso, seguimos los siguientes pasos.
- Cree un árbol de segmentos para que podamos encontrar rápidamente GCD de cualquier subarreglo utilizando el enfoque discutido aquí
- Después de construir el árbol de segmentos, consideramos cada índice como punto de partida y hacemos una búsqueda binaria para el punto final de modo que el subarreglo entre estos dos puntos tenga GCD k
A continuación se muestra la implementación de la idea anterior.
C++
// C++ Program to find GCD of a number in a given Range // using segment Trees #include <bits/stdc++.h> using namespace std; // To store segment tree int *st; // Function to find gcd of 2 numbers. int gcd(int a, int b) { if (a < b) swap(a, b); if (b==0) return a; return gcd(b, a%b); } /* A recursive function to get gcd of given range of array indexes. The following are parameters for this function. st --> Pointer to segment tree si --> Index of current node in the segment tree. Initially 0 is passed as root is always at index 0 ss & se --> Starting and ending indexes of the segment represented by current node, i.e., st[index] qs & qe --> Starting and ending indexes of query range */ int findGcd(int ss, int se, int qs, int qe, int si) { if (ss>qe || se < qs) return 0; if (qs<=ss && qe>=se) return st[si]; int mid = ss+(se-ss)/2; return gcd(findGcd(ss, mid, qs, qe, si*2+1), findGcd(mid+1, se, qs, qe, si*2+2)); } //Finding The gcd of given Range int findRangeGcd(int ss, int se, int arr[], int n) { if (ss<0 || se > n-1 || ss>se) { cout << "Invalid Arguments" << "\n"; return -1; } return findGcd(0, n-1, ss, se, 0); } // A recursive function that constructs Segment Tree for // array[ss..se]. si is index of current node in segment // tree st int constructST(int arr[], int ss, int se, int si) { if (ss==se) { st[si] = arr[ss]; return st[si]; } int mid = ss+(se-ss)/2; st[si] = gcd(constructST(arr, ss, mid, si*2+1), constructST(arr, mid+1, se, si*2+2)); return st[si]; } /* Function to construct segment tree from given array. This function allocates memory for segment tree and calls constructSTUtil() to fill the allocated memory */ int *constructSegmentTree(int arr[], int n) { int height = (int)(ceil(log2(n))); int size = 2*(int)pow(2, height)-1; st = new int[size]; constructST(arr, 0, n-1, 0); return st; } // Returns size of smallest subarray of arr[0..n-1] // with GCD equal to k. int findSmallestSubarr(int arr[], int n, int k) { // To check if a multiple of k exists. bool found = false; // Find if k or its multiple is present for (int i=0; i<n; i++) { // If k is present, then subarray size is 1. if (arr[i] == k) return 1; // Break the loop to indicate presence of a // multiple of k. if (arr[i] % k == 0) found = true; } // If there was no multiple of k in arr[], then // we can't get k as GCD. if (found == false) return -1; // If there is a multiple of k in arr[], build // segment tree from given array constructSegmentTree(arr, n); // Initialize result int res = n+1; // Now consider every element as starting point // and search for ending point using Binary Search for (int i=0; i<n-1; i++) { // a[i] cannot be a starting point, if it is // not a multiple of k. if (arr[i] % k != 0) continue; // Initialize indexes for binary search of closest // ending point to i with GCD of subarray as k. int low = i+1; int high = n-1; // Initialize closest ending point for i. int closest = 0; // Binary Search for closest ending point // with GCD equal to k. while (true) { // Find middle point and GCD of subarray // arr[i..mid] int mid = low + (high-low)/2; int gcd = findRangeGcd(i, mid, arr, n); // If GCD is more than k, look further if (gcd > k) low = mid; // If GCD is k, store this point and look for // a closer point else if (gcd == k) { high = mid; closest = mid; } // If GCD is less than, look closer else high = mid; // If termination condition reached, set // closest if (abs(high-low) <= 1) { if (findRangeGcd(i, low, arr, n) == k) closest = low; else if (findRangeGcd(i, high, arr, n)==k) closest = high; break; } } if (closest != 0) res = min(res, closest - i + 1); } // If res was not changed by loop, return -1, // else return its value. return (res == n+1) ? -1 : res; } // Driver program to test above functions int main() { int n = 8; int k = 3; int arr[] = {6, 9, 7, 10, 12, 24, 36, 27}; cout << "Size of smallest sub-array with given" << " size is " << findSmallestSubarr(arr, n, k); return 0; }
Java
// Java Program to find GCD of a number in a given Range // using segment Trees class GFG { // To store segment tree static int []st; // Function to find gcd of 2 numbers. static int gcd(int a, int b) { if (a < b) swap(a, b); if (b == 0) return a; return gcd(b, a % b); } private static void swap(int x, int y) { int temp = x; x = y; y = temp; } /* A recursive function to get gcd of given range of array indexes. The following are parameters for this function. st --> Pointer to segment tree si --> Index of current node in the segment tree. Initially 0 is passed as root is always at index 0 ss & se --> Starting and ending indexes of the segment represented by current node, i.e., st[index] qs & qe --> Starting and ending indexes of query range */ static int findGcd(int ss, int se, int qs, int qe, int si) { if (ss > qe || se < qs) return 0; if (qs <= ss && qe >= se) return st[si]; int mid = ss + (se - ss) / 2; return gcd(findGcd(ss, mid, qs, qe, si * 2 + 1), findGcd(mid + 1, se, qs, qe, si * 2 + 2)); } // Finding The gcd of given Range static int findRangeGcd(int ss, int se, int arr[], int n) { if (ss < 0 || se > n-1 || ss > se) { System.out.println("Invalid Arguments"); return -1; } return findGcd(0, n - 1, ss, se, 0); } // A recursive function that constructs Segment Tree for // array[ss..se]. si is index of current node in segment // tree st static int constructST(int arr[], int ss, int se, int si) { if (ss == se) { st[si] = arr[ss]; return st[si]; } int mid = ss + (se - ss) / 2; st[si] = gcd(constructST(arr, ss, mid, si * 2 + 1), constructST(arr, mid+1, se, si * 2 + 2)); return st[si]; } /* Function to construct segment tree from given array. This function allocates memory for segment tree and calls constructSTUtil() to fill the allocated memory */ static int []constructSegmentTree(int arr[], int n) { int height = (int)(Math.ceil(Math.log(n))); int size = 2*(int)Math.pow(2, height) - 1; st = new int[size]; constructST(arr, 0, n - 1, 0); return st; } // Returns size of smallest subarray of arr[0..n-1] // with GCD equal to k. static int findSmallestSubarr(int arr[], int n, int k) { // To check if a multiple of k exists. boolean found = false; // Find if k or its multiple is present for (int i = 0; i < n; i++) { // If k is present, then subarray size is 1. if (arr[i] == k) return 1; // Break the loop to indicate presence of a // multiple of k. if (arr[i] % k == 0) found = true; } // If there was no multiple of k in arr[], then // we can't get k as GCD. if (found == false) return -1; // If there is a multiple of k in arr[], build // segment tree from given array constructSegmentTree(arr, n); // Initialize result int res = n + 1; // Now consider every element as starting point // and search for ending point using Binary Search for (int i = 0; i < n - 1; i++) { // a[i] cannot be a starting point, if it is // not a multiple of k. if (arr[i] % k != 0) continue; // Initialize indexes for binary search of closest // ending point to i with GCD of subarray as k. int low = i + 1; int high = n - 1; // Initialize closest ending point for i. int closest = 0; // Binary Search for closest ending point // with GCD equal to k. while (true) { // Find middle point and GCD of subarray // arr[i..mid] int mid = low + (high-low)/2; int gcd = findRangeGcd(i, mid, arr, n); // If GCD is more than k, look further if (gcd > k) low = mid; // If GCD is k, store this point and look for // a closer point else if (gcd == k) { high = mid; closest = mid; } // If GCD is less than, look closer else high = mid; // If termination condition reached, set // closest if (Math.abs(high-low) <= 1) { if (findRangeGcd(i, low, arr, n) == k) closest = low; else if (findRangeGcd(i, high, arr, n)==k) closest = high; break; } } if (closest != 0) res = Math.min(res, closest - i + 1); } // If res was not changed by loop, return -1, // else return its value. return (res == n+1) ? -1 : res; } // Driver code public static void main(String args[]) { int n = 8; int k = 3; int arr[] = {6, 9, 7, 10, 12, 24, 36, 27}; System.out.println("Size of smallest sub-array with given" + " size is " + findSmallestSubarr(arr, n, k)); } } // This code is contributed by Rajput-Ji
Python3
# Python Program to find GCD of a number in a given Range # using segment Trees # To store segment tree st = [] # Function to find gcd of 2 numbers. def gcd(a: int, b: int) -> int: if a < b: a, b = b, a if b == 0: return a return gcd(b, a % b) # A recursive function to get gcd of given # range of array indexes. The following are parameters for # this function. # st --> Pointer to segment tree # si --> Index of current node in the segment tree. Initially # 0 is passed as root is always at index 0 # ss & se --> Starting and ending indexes of the segment # represented by current node, i.e., st[index] # qs & qe --> Starting and ending indexes of query range def findGcd(ss: int, se: int, qs: int, qe: int, si: int) -> int: if ss > qe or se < qs: return 0 if qs <= ss and qe >= se: return st[si] mid = ss + (se - ss) // 2 return gcd(findGcd(ss, mid, qs, qe, si * 2 + 1), findGcd(mid + 1, se, qs, qe, si * 2 + 2)) # Finding The gcd of given Range def findRangeGcd(ss: int, se: int, arr: list, n: int) -> int: if ss < 0 or se > n - 1 or ss > se: print("invalid Arguments") return -1 return findGcd(0, n - 1, ss, se, 0) # A recursive function that constructs Segment Tree for # array[ss..se]. si is index of current node in segment # tree st def constructST(arr: list, ss: int, se: int, si: int) -> int: if ss == se: st[si] = arr[ss] return st[si] mid = ss + (se - ss) // 2 st[si] = gcd(constructST(arr, ss, mid, si * 2 + 1), constructST(arr, mid + 1, se, si * 2 + 2)) return st[si] # Function to construct segment tree from given array. # This function allocates memory for segment tree and # calls constructSTUtil() to fill the allocated memory def constructSegmentTree(arr: list, n: int) -> list: global st from math import ceil, log2, pow height = int(ceil(log2(n))) size = 2 * int(pow(2, height)) - 1 st = [0] * size constructST(arr, 0, n - 1, 0) return st # Returns size of smallest subarray of arr[0..n-1] # with GCD equal to k. def findSmallestSubarr(arr: list, n: int, k: int) -> int: # To check if a multiple of k exists. found = False # Find if k or its multiple is present for i in range(n): # If k is present, then subarray size is 1. if arr[i] == k: return 1 # Break the loop to indicate presence of a # multiple of k. if arr[i] % k == 0: found = True # If there was no multiple of k in arr[], then # we can't get k as GCD. if found == False: return -1 # If there is a multiple of k in arr[], build # segment tree from given array constructSegmentTree(arr, n) # Initialize result res = n + 1 # Now consider every element as starting point # and search for ending point using Binary Search for i in range(n - 1): # a[i] cannot be a starting point, if it is # not a multiple of k. if arr[i] % k != 0: continue # Initialize indexes for binary search of closest # ending point to i with GCD of subarray as k. low = i + 1 high = n - 1 # Initialize closest ending point for i. closest = 0 # Binary Search for closest ending point # with GCD equal to k. while True: # Find middle point and GCD of subarray # arr[i..mid] mid = low + (high - low) // 2 gcd = findRangeGcd(i, mid, arr, n) # If GCD is more than k, look further if gcd > k: low = mid # If GCD is k, store this point and look for # a closer point else if gcd == k: high = mid closest = mid # If GCD is less than, look closer else: high = mid # If termination condition reached, set # closest if abs(high - low) <= 1: if findRangeGcd(i, low, arr, n) == k: closest = low else if findRangeGcd(i, high, arr, n) == k: closest = high break if closest != 0: res = min(res, closest - i + 1) # If res was not changed by loop, return -1, # else return its value. return -1 if res == n + 1 else res # Driver Code if __name__ == "__main__": n = 8 k = 3 arr = [6, 9, 7, 10, 12, 24, 36, 27] print("Size of smallest sub-array with given size is", findSmallestSubarr(arr, n, k)) # This code is contributed by # sanjeev2552
C#
// C# Program to find GCD of a number in a given Range // using segment Trees using System; class GFG { // To store segment tree static int []st; // Function to find gcd of 2 numbers. static int gcd(int a, int b) { if (a < b) swap(a, b); if (b == 0) return a; return gcd(b, a % b); } private static void swap(int x, int y) { int temp = x; x = y; y = temp; } /* A recursive function to get gcd of given range of array indexes. The following are parameters for this function. st --> Pointer to segment tree si --> Index of current node in the segment tree. Initially 0 is passed as root is always at index 0 ss & se --> Starting and ending indexes of the segment represented by current node, i.e., st[index] qs & qe --> Starting and ending indexes of query range */ static int findGcd(int ss, int se, int qs, int qe, int si) { if (ss > qe || se < qs) return 0; if (qs <= ss && qe >= se) return st[si]; int mid = ss + (se - ss) / 2; return gcd(findGcd(ss, mid, qs, qe, si * 2 + 1), findGcd(mid + 1, se, qs, qe, si * 2 + 2)); } // Finding The gcd of given Range static int findRangeGcd(int ss, int se, int []arr, int n) { if (ss < 0 || se > n-1 || ss > se) { Console.WriteLine("Invalid Arguments"); return -1; } return findGcd(0, n - 1, ss, se, 0); } // A recursive function that constructs Segment Tree for // array[ss..se]. si is index of current node in segment // tree st static int constructST(int []arr, int ss, int se, int si) { if (ss == se) { st[si] = arr[ss]; return st[si]; } int mid = ss + (se - ss) / 2; st[si] = gcd(constructST(arr, ss, mid, si * 2 + 1), constructST(arr, mid+1, se, si * 2 + 2)); return st[si]; } /* Function to construct segment tree from given array. This function allocates memory for segment tree and calls constructSTUtil() to fill the allocated memory */ static int []constructSegmentTree(int []arr, int n) { int height = (int)(Math.Ceiling(Math.Log(n))); int size = 2*(int)Math.Pow(2, height) - 1; st = new int[size]; constructST(arr, 0, n - 1, 0); return st; } // Returns size of smallest subarray of arr[0..n-1] // with GCD equal to k. static int findSmallestSubarr(int []arr, int n, int k) { // To check if a multiple of k exists. bool found = false; // Find if k or its multiple is present for (int i = 0; i < n; i++) { // If k is present, then subarray size is 1. if (arr[i] == k) return 1; // Break the loop to indicate presence of a // multiple of k. if (arr[i] % k == 0) found = true; } // If there was no multiple of k in arr[], then // we can't get k as GCD. if (found == false) return -1; // If there is a multiple of k in arr[], build // segment tree from given array constructSegmentTree(arr, n); // Initialize result int res = n + 1; // Now consider every element as starting point // and search for ending point using Binary Search for (int i = 0; i < n - 1; i++) { // a[i] cannot be a starting point, if it is // not a multiple of k. if (arr[i] % k != 0) continue; // Initialize indexes for binary search of closest // ending point to i with GCD of subarray as k. int low = i + 1; int high = n - 1; // Initialize closest ending point for i. int closest = 0; // Binary Search for closest ending point // with GCD equal to k. while (true) { // Find middle point and GCD of subarray // arr[i..mid] int mid = low + (high-low)/2; int gcd = findRangeGcd(i, mid, arr, n); // If GCD is more than k, look further if (gcd > k) low = mid; // If GCD is k, store this point and look for // a closer point else if (gcd == k) { high = mid; closest = mid; } // If GCD is less than, look closer else high = mid; // If termination condition reached, set // closest if (Math.Abs(high-low) <= 1) { if (findRangeGcd(i, low, arr, n) == k) closest = low; else if (findRangeGcd(i, high, arr, n)==k) closest = high; break; } } if (closest != 0) res = Math.Min(res, closest - i + 1); } // If res was not changed by loop, return -1, // else return its value. return (res == n+1) ? -1 : res; } // Driver code public static void Main(String []args) { int n = 8; int k = 3; int []arr = {6, 9, 7, 10, 12, 24, 36, 27}; Console.WriteLine("Size of smallest sub-array with given" + " size is " + findSmallestSubarr(arr, n, k)); } } /* This code is contributed by PrinciRaj1992 */
Javascript
<script> // Javascript Program to find GCD of a number in a given Range // using segment Trees // To store segment tree var st = []; // Function to find gcd of 2 numbers. function gcd(a, b) { if (a < b) [a, b] = [b,a]; if (b == 0) return a; return gcd(b, a % b); } /* A recursive function to get gcd of given range of array indexes. The following are parameters for this function. st --> Pointer to segment tree si --> Index of current node in the segment tree. Initially 0 is passed as root is always at index 0 ss & se --> Starting and ending indexes of the segment represented by current node, i.e., st[index] qs & qe --> Starting and ending indexes of query range */ function findGcd(ss, se, qs, qe, si) { if (ss > qe || se < qs) return 0; if (qs <= ss && qe >= se) return st[si]; var mid = ss + parseInt((se - ss) / 2); return gcd(findGcd(ss, mid, qs, qe, si * 2 + 1), findGcd(mid + 1, se, qs, qe, si * 2 + 2)); } // Finding The gcd of given Range function findRangeGcd(ss, se, arr, n) { if (ss < 0 || se > n-1 || ss > se) { document.write("Invalid Arguments"); return -1; } return findGcd(0, n - 1, ss, se, 0); } // A recursive function that constructs Segment Tree for // array[ss..se]. si is index of current node in segment // tree st function constructST(arr, ss, se, si) { if (ss == se) { st[si] = arr[ss]; return st[si]; } var mid = ss + parseInt((se - ss) / 2); st[si] = gcd(constructST(arr, ss, mid, si * 2 + 1), constructST(arr, mid+1, se, si * 2 + 2)); return st[si]; } /* Function to construct segment tree from given array. This function allocates memory for segment tree and calls constructSTUtil() to fill the allocated memory */ function constructSegmentTree(arr, n) { var height = parseInt(Math.ceil(Math.log(n))); var size = 2*parseInt(Math.pow(2, height)) - 1; st = Array(size).fill(0); constructST(arr, 0, n - 1, 0); return st; } // Returns size of smallest subarray of arr[0..n-1] // with GCD equal to k. function findSmallestSubarr(arr, n, k) { // To check if a multiple of k exists. var found = false; // Find if k or its multiple is present for (var i = 0; i < n; i++) { // If k is present, then subarray size is 1. if (arr[i] == k) return 1; // Break the loop to indicate presence of a // multiple of k. if (arr[i] % k == 0) found = true; } // If there was no multiple of k in arr[], then // we can't get k as GCD. if (found == false) return -1; // If there is a multiple of k in arr[], build // segment tree from given array constructSegmentTree(arr, n); // Initialize result var res = n + 1; // Now consider every element as starting point // and search for ending point using Binary Search for (var i = 0; i < n - 1; i++) { // a[i] cannot be a starting point, if it is // not a multiple of k. if (arr[i] % k != 0) continue; // Initialize indexes for binary search of closest // ending point to i with GCD of subarray as k. var low = i + 1; var high = n - 1; // Initialize closest ending point for i. var closest = 0; // Binary Search for closest ending point // with GCD equal to k. while (true) { // Find middle point and GCD of subarray // arr[i..mid] var mid = low + parseInt((high-low)/2); var gcd = findRangeGcd(i, mid, arr, n); // If GCD is more than k, look further if (gcd > k) low = mid; // If GCD is k, store this point and look for // a closer point else if (gcd == k) { high = mid; closest = mid; } // If GCD is less than, look closer else high = mid; // If termination condition reached, set // closest if (Math.abs(high-low) <= 1) { if (findRangeGcd(i, low, arr, n) == k) closest = low; else if (findRangeGcd(i, high, arr, n)==k) closest = high; break; } } if (closest != 0) res = Math.min(res, closest - i + 1); } // If res was not changed by loop, return -1, // else return its value. return (res == n+1) ? -1 : res; } // Driver code var n = 8; var k = 3; var arr = [6, 9, 7, 10, 12, 24, 36, 27]; document.write("Size of smallest sub-array with given" + " size is " + findSmallestSubarr(arr, n, k)); // This code is contributed by itsok. </script>
Size of smallest sub-array with given size is 2
Ejemplo:
arr[] = {6, 9, 7, 10, 12, 24, 36, 27}, K = 3 // Initial value of minLen is equal to size // of array minLen = 8 No element is equal to k so result is either greater than 1 or doesn't exist.
primer índice
- MCD del subarreglo de 1 a 5 es 1.
- MCD < k
- MCD del subarreglo de 1 a 3 es 1.
- MCD < k
- GCD del subarreglo de 1 a 2 es 3
- minLen = mínimo (8, 2) = 2
Segundo Índice
- MCD del subarreglo de 2 a 5 es 1
- MCD < k
- MCD del subarreglo de 2 a 4 es 1
- MCD < k
- MCD del subarreglo de 6 a 8 es 3
- minLen = mínimo (2, 3) = 2.
.
.
.
Sexto Índice
- MCD del subarreglo de 6 a 7 es 12
- MCD > k
- MCD del subarreglo de 6 a 8 es 3
- minLen = mínimo (2, 3) = 2
Complejidad de tiempo: O(n (logn) 2 ) , O(n) para atravesar cada índice, O(logn) para cada subarreglo y O(logn) para GCD de cada subarreglo.
Este artículo es una contribución de Nikhil Tekwani. Si le gusta GeeksforGeeks y le gustaría contribuir, también puede escribir un artículo y enviarlo por correo a review-team@geeksforgeeks.org. Vea su artículo que aparece en la página principal de GeeksforGeeks y ayude a otros Geeks.
Publicación traducida automáticamente
Artículo escrito por GeeksforGeeks-1 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA