Minimum index to split array into subarrays with co-prime products
Last Updated :
21 Oct, 2023
Given an array arr[] consisting of N integers, the task is to find the maximum index K such that the product of subarrays {arr[0], arr[K]} and {arr[K + 1], arr[N – 1]} are co-prime. If no such index exists, then print “-1”.
Examples:
Input: arr[] = {2, 3, 4, 5}
Output: 2
Explanation:
Smallest index for partition is 2.
Product of left subarray is = 2 * 3 * 4 = 24.
Product of right subarray = 5.
Since 24 and 5 are co-prime, the required answer is 2.
Input: arr[] = {23, 41, 52, 83, 7, 13}
Output: 0
Explanation:
Smallest index for partition is 0.
Product of left subarray = 23.
Product of right subarray = 41 * 52 * 83 * 7 * 13 = 16102996.
Since 23 and 16102996 are co-prime, the answer is 0.
Naive Approach: The simplest approach is to check all possible indexes of partition from the start of the array and check if the product of the subarrays formed is co-prime or not. If there exists any such index then print that index. Otherwise, print “-1”.
Time Complexity: O(N2)
Auxiliary Space: O(1)
Better Approach: To optimize the above approach, the idea is to use the prefix product array and suffix product array and find the possible index. Follow the steps below to solve the problem:
- Create two auxiliary arrays, prefix[] and suffix[] to store the prefix and suffix array product. Initialize prefix[0] to arr[0] and suffix[N – 1] to arr[N – 1].
- Traverse the given array over the range [2, N] using variable i and update the prefix array as prefix[i] = prefix[i – 1]*arr[i].
- Traverse the given array from the back over the range [N – 2, 0] using variable i and update the suffix array as suffix[i] = suffix[i + 1]*arr[i].
- Iterate a loop over the range [0, N – 1] using variable i and check if prefix[i] and suffix[i + 1] are co-prime or not. If found to be true the print the current index and break out of the loop.
- If there doesn’t exist any such index in the above step then print “-1”.
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
int GCD( int a, int b)
{
if (b == 0)
return a;
return GCD(b, a % b);
}
int findPartition( int nums[], int N)
{
int prefix[N], suffix[N], i, k;
prefix[0] = nums[0];
for (i = 1; i < N; i++) {
prefix[i] = prefix[i - 1]
* nums[i];
}
suffix[N - 1] = nums[N - 1];
for (i = N - 2; i >= 0; i--) {
suffix[i] = suffix[i + 1]
* nums[i];
}
for (k = 0; k < N - 1; k++) {
if (GCD(prefix[k],
suffix[k + 1])
== 1) {
return k;
}
}
return -1;
}
int main()
{
int arr[] = { 2, 3, 4, 5 };
int N = sizeof (arr) / sizeof (arr[0]);
cout << findPartition(arr, N);
return 0;
}
|
Java
import java.util.*;
class solution{
static int GCD( int a,
int b)
{
if (b == 0 )
return a;
return GCD(b, a % b);
}
static int findPartition( int nums[],
int N)
{
int []prefix = new int [N];
int []suffix = new int [N];
int i, k;
prefix[ 0 ] = nums[ 0 ];
for (i = 1 ; i < N; i++)
{
prefix[i] = prefix[i - 1 ] *
nums[i];
}
suffix[N - 1 ] = nums[N - 1 ];
for (i = N - 2 ; i >= 0 ; i--)
{
suffix[i] = suffix[i + 1 ] *
nums[i];
}
for (k = 0 ; k < N - 1 ; k++)
{
if (GCD(prefix[k],
suffix[k + 1 ]) == 1 )
{
return k;
}
}
return - 1 ;
}
public static void main(String args[])
{
int arr[] = { 2 , 3 , 4 , 5 };
int N = arr.length;
System.out.println(findPartition(arr, N));
}
}
|
Python3
def GCD(a, b):
if (b = = 0 ):
return a
return GCD(b, a % b)
def findPartition(nums, N):
prefix = [ 0 ] * N
suffix = [ 0 ] * N
prefix[ 0 ] = nums[ 0 ]
for i in range ( 1 , N):
prefix[i] = (prefix[i - 1 ] *
nums[i])
suffix[N - 1 ] = nums[N - 1 ]
for i in range (N - 2 , - 1 , - 1 ):
suffix[i] = (suffix[i + 1 ] *
nums[i])
for k in range (N - 1 ):
if (GCD(prefix[k],
suffix[k + 1 ]) = = 1 ):
return k
return - 1
if __name__ = = '__main__' :
arr = [ 2 , 3 , 4 , 5 ]
N = len (arr)
print (findPartition(arr, N))
|
C#
using System;
class GFG{
static int GCD( int a, int b)
{
if (b == 0)
return a;
return GCD(b, a % b);
}
static int findPartition( int [] nums,
int N)
{
int [] prefix = new int [N];
int [] suffix = new int [N];
int i, k;
prefix[0] = nums[0];
for (i = 1; i < N; i++)
{
prefix[i] = prefix[i - 1] *
nums[i];
}
suffix[N - 1] = nums[N - 1];
for (i = N - 2; i >= 0; i--)
{
suffix[i] = suffix[i + 1] *
nums[i];
}
for (k = 0; k < N - 1; k++)
{
if (GCD(prefix[k],
suffix[k + 1]) == 1)
{
return k;
}
}
return -1;
}
static void Main()
{
int [] arr = {2, 3, 4, 5};
int N = arr.Length;
Console.WriteLine(findPartition(arr, N));
}
}
|
Javascript
<script>
function GCD(a, b)
{
if (b == 0)
return a;
return GCD(b, a % b);
}
function findPartition(nums, N)
{
var prefix = Array(N), suffix = Array(N), i, k;
prefix[0] = nums[0];
for (i = 1; i < N; i++) {
prefix[i] = prefix[i - 1]
* nums[i];
}
suffix[N - 1] = nums[N - 1];
for (i = N - 2; i >= 0; i--) {
suffix[i] = suffix[i + 1]
* nums[i];
}
for (k = 0; k < N - 1; k++) {
if (GCD(prefix[k],
suffix[k + 1])
== 1) {
return k;
}
}
return -1;
}
var arr = [2, 3, 4, 5];
var N = arr.length;
document.write( findPartition(arr, N));
</script>
|
Time Complexity: O(N log(N))
Auxiliary Space: O(N)
Efficient Approach: Above approach is using a prefix array and suffix array that stores the product of numbers , if the product of numbers exceeds the integer maximum value then it will lead to overflow , hence a different approach is needed such that it will work for every numbers that are present in the array. Follow the steps below to solve the problem:
- Create a frequency map total_freq that will store the count of all the prime factors of numbers that are present in the array using the primeFreq function that will calculate prime factors of number.
- Create an another frequency map curr_freq that will store the count of prime factors of current numbers of array.
- Iterate over array elements and create a boolean flg with value set to true and store the current prime divisors of number in curr_freq map. Then Iterate over the map curr_freq and check if the current prime factor count in curr_freq map and total_freq map are equal or not. If it is not equal then set flg to false and stop iteration of the curr_freq map and break.
- After that check if flg is true then return the value of current array element’s index that is giving this result.
- If there doesn’t exist any such index then print “-1“.
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
void primeFreq( int x, unordered_map< int , int >& freq)
{
int temp = x;
for ( int i = 2; i <= sqrt (x); i++) {
while (temp % i == 0) {
freq[i]++;
temp /= i;
}
}
if (temp > 1) {
freq[temp]++;
}
}
int findValidSplit(vector< int >& nums)
{
unordered_map< int , int > freq;
for ( auto i : nums) {
primeFreq(i, freq);
}
unordered_map< int , int > curr_freq;
for ( int i = 0; i < nums.size(); i++) {
primeFreq(nums[i], curr_freq);
bool f = true ;
for ( auto j : curr_freq) {
if (freq[j.first] - j.second > 0) {
f = false ;
break ;
}
}
if (f && i != nums.size() - 1)
return i;
}
return -1;
}
int main()
{
vector< int > arr(4);
arr[0] = 2;
arr[1] = 3;
arr[2] = 4;
arr[3] = 5;
cout << findValidSplit(arr);
return 0;
}
|
Java
import java.util.*;
public class Main {
public static void primeFreq( int x, HashMap<Integer, Integer> freq) {
int temp = x;
for ( int i = 2 ; i <= Math.sqrt(x); i++) {
while (temp % i == 0 ) {
freq.put(i, freq.getOrDefault(i, 0 ) + 1 );
temp /= i;
}
}
if (temp > 1 ) {
freq.put(temp, freq.getOrDefault(temp, 0 ) + 1 );
}
}
public static int findValidSplit(ArrayList<Integer> nums) {
HashMap<Integer, Integer> freq = new HashMap<>();
for ( int i : nums) {
primeFreq(i, freq);
}
HashMap<Integer, Integer> currFreq = new HashMap<>();
for ( int i = 0 ; i < nums.size(); i++) {
primeFreq(nums.get(i), currFreq);
boolean f = true ;
for (Map.Entry<Integer, Integer> entry : currFreq.entrySet()) {
int key = entry.getKey();
int value = entry.getValue();
if (freq.getOrDefault(key, 0 ) - value > 0 ) {
f = false ;
break ;
}
}
if (f && i != nums.size() - 1 )
return i;
}
return - 1 ;
}
public static void main(String[] args) {
ArrayList<Integer> arr = new ArrayList<>();
arr.add( 2 );
arr.add( 3 );
arr.add( 4 );
arr.add( 5 );
System.out.println(findValidSplit(arr));
}
}
|
Python3
from math import sqrt
from collections import defaultdict
def primeFreq(x, freq):
temp = x
i = 2
while i < = sqrt(x):
while temp % i = = 0 :
freq[i] + = 1
temp / / = i
i + = 1
if temp > 1 :
freq[temp] + = 1
def findValidSplit(nums):
freq = defaultdict( int )
for i in nums:
primeFreq(i, freq)
curr_freq = defaultdict( int )
for i in range ( len (nums)):
primeFreq(nums[i], curr_freq)
f = True
for j in curr_freq.items():
if freq[j[ 0 ]] - j[ 1 ] > 0 :
f = False
break
if f and i ! = len (nums) - 1 :
return i
return - 1
arr = [ 2 , 3 , 4 , 5 ]
print (findValidSplit(arr))
|
C#
using System;
using System.Collections.Generic;
class MainClass {
public static void PrimeFreq( int x, Dictionary< int , int > freq) {
int temp = x;
for ( int i = 2; i * i <= x; i++) {
while (temp % i == 0) {
if (freq.ContainsKey(i)) {
freq[i]++;
}
else {
freq[i] = 1;
}
temp /= i;
}
}
if (temp > 1) {
if (freq.ContainsKey(temp)) {
freq[temp]++;
}
else {
freq[temp] = 1;
}
}
}
public static int FindValidSplit(List< int > nums) {
Dictionary< int , int > freq = new Dictionary< int , int >();
foreach ( int num in nums) {
PrimeFreq(num, freq);
}
Dictionary< int , int > currFreq = new Dictionary< int , int >();
for ( int i = 0; i < nums.Count; i++) {
PrimeFreq(nums[i], currFreq);
bool isValidSplit = true ;
foreach (KeyValuePair< int , int > entry in currFreq) {
int key = entry.Key;
int value = entry.Value;
if (freq.ContainsKey(key) && freq[key] - value > 0) {
isValidSplit = false ;
break ;
}
}
if (isValidSplit && i != nums.Count - 1) {
return i;
}
}
return -1;
}
public static void Main( string [] args) {
List< int > arr = new List< int >();
arr.Add(2);
arr.Add(3);
arr.Add(4);
arr.Add(5);
Console.WriteLine(FindValidSplit(arr));
}
}
|
Javascript
function primeFreq(x, freq) {
let temp = x;
for (let i = 2; i <= Math.sqrt(x); i++) {
while (temp % i === 0) {
freq[i]++;
temp = Math.floor(temp/x);
}
}
if (temp > 1) {
if (freq[temp])
freq[temp]++;
else
freq[temp] = 1;
}
}
function findValidSplit(nums) {
const freq = {};
for (let i = 0; i < nums.length; i++) {
primeFreq(nums[i], freq);
}
const currFreq = {};
for (let i = 0; i < nums.length; i++) {
primeFreq(nums[i], currFreq);
let f = true ;
for (const j in currFreq) {
if (freq[j] - currFreq[j] > 0) {
f = false ;
break ;
}
}
if (f && i !== nums.length - 1) {
return i;
}
}
return -1;
}
let arr = new Array(4);
arr[0] = 2;
arr[1] = 3;
arr[2] = 4;
arr[3] = 5;
console.log(findValidSplit(arr));
|
Output
2
Time Complexity: O(N*sqrt(N))
Auxiliary Space: O(N)
Like Article
Suggest improvement
Share your thoughts in the comments
Please Login to comment...