Number of GP (Geometric Progression) subsequences of size 3
Given n elements and a ratio r, find the number of G.P. subsequences with length 3. A subsequence is considered GP with length 3 with ration r.
Examples:
Input : arr[] = {1, 1, 2, 2, 4}
r = 2
Output : 4
Explanation: Any of the two 1s can be chosen
as the first element, the second element can
be any of the two 2s, and the third element
of the subsequence must be equal to 4.
Input : arr[] = {1, 1, 2, 2, 4}
r = 3
Output : 0
A naive approach is to use three nested for loops and check for every subsequence with length 3 and keep a count of the subsequences. The complexity is O(n3).
An efficient approach is to solve the problem for the fixed middle element of progression. This means that if we fix element a[i] as middle, then it must be multiple of r, and a[i]/r and a[i]*r must be present. We count the number of occurrences of a[i]/r and a[i]*r and then multiply the counts. To do this, we can use the concept of hashing where we store the count of all possible elements in two hash maps, one indicating the number of elements on the left and the other indicating the number of elements to the right.
Below is the implementation of the above approach
C++
#include <bits/stdc++.h>
using namespace std;
long long subsequences( int a[], int n, int r)
{
unordered_map< int , int > left, right;
long long ans = 0;
for ( int i = 0; i < n; i++)
right[a[i]]++;
for ( int i = 0; i < n; i++) {
long long c1 = 0, c2 = 0;
if (a[i] % r == 0)
c1 = left[a[i] / r];
right[a[i]]--;
c2 = right[a[i] * r];
ans += c1 * c2;
left[a[i]]++;
}
return ans;
}
int main()
{
int a[] = { 1, 2, 6, 2, 3, 6, 9, 18, 3, 9 };
int n = sizeof (a) / sizeof (a[0]);
int r = 3;
cout << subsequences(a, n, r);
return 0;
}
|
Java
import java.util.*;
import java.lang.*;
class GFG{
static long subsequences( int a[], int n, int r)
{
Map<Integer, Integer> left = new HashMap<>(),
right = new HashMap<>();
long ans = 0 ;
for ( int i = 0 ; i < n; i++)
right.put(a[i],
right.getOrDefault(a[i], 0 ) + 1 );
for ( int i = 0 ; i < n; i++)
{
long c1 = 0 , c2 = 0 ;
if (a[i] % r == 0 )
c1 = left.getOrDefault(a[i] / r, 0 );
right.put(a[i],
right.getOrDefault(a[i], 0 ) - 1 );
c2 = right.getOrDefault(a[i] * r, 0 );
ans += c1 * c2;
left.put(a[i],
left.getOrDefault(a[i], 0 ) + 1 );
}
return ans;
}
public static void main (String[] args)
{
int a[] = { 1 , 2 , 6 , 2 , 3 ,
6 , 9 , 18 , 3 , 9 };
int n = a.length;
int r = 3 ;
System.out.println(subsequences(a, n, r));
}
}
|
Python3
from collections import defaultdict
def subsequences(a, n, r):
left = defaultdict( lambda : 0 )
right = defaultdict( lambda : 0 )
ans = 0
for i in range ( 0 , n):
right[a[i]] + = 1
for i in range ( 0 , n):
c1, c2 = 0 , 0
if a[i] % r = = 0 :
c1 = left[a[i] / / r]
right[a[i]] - = 1
c2 = right[a[i] * r]
ans + = c1 * c2
left[a[i]] + = 1
return ans
if __name__ = = "__main__" :
a = [ 1 , 2 , 6 , 2 , 3 , 6 , 9 , 18 , 3 , 9 ]
n = len (a)
r = 3
print (subsequences(a, n, r))
|
C#
using System;
using System.Collections.Generic;
class GFG{
static long subsequences( int []a,
int n, int r)
{
Dictionary< int ,
int > left =
new Dictionary< int ,
int >(),
right = new Dictionary< int ,
int >();
long ans = -1;
for ( int i = 0; i < n; i++)
if (right.ContainsKey(a[i]))
right[a[i]] = right[a[i]] + 1;
else
right.Add(a[i], 1);
for ( int i = 0; i < n; i++)
{
long c1 = 0, c2 = 0;
if (a[i] % r == 0)
if (left.ContainsKey(a[i] / r))
c1 = right[a[i] / r];
else
c1 = 0;
if (right.ContainsKey(a[i]))
right[a[i]] = right[a[i]];
else
right.Add(a[i], -1);
if (right.ContainsKey(a[i] * r))
c2 = right[a[i] * r];
else
c2 = 0;
ans += (c1 * c2);
if (left.ContainsKey(a[i]))
left[a[i]] = 0;
else
left.Add(a[i], 1);
}
return ans - 1;
}
public static void Main(String[] args)
{
int []a = {1, 2, 6, 2, 3,
6, 9, 18, 3, 9};
int n = a.Length;
int r = 3;
Console.WriteLine(subsequences(a,
n, r));
}
}
|
Javascript
<script>
function subsequences(a, n, r)
{
let left = new Map(), right = new Map();
let ans = 0;
for (let i = 0; i < n; i++){
if (right.has(a[i])){
right.set(a[i],right.get(a[i])+1);
}
else right.set(a[i],1);
}
for (let i = 0; i < n; i++) {
let c1 = 0, c2 = 0;
if (a[i] % r == 0)
c1 = left.has(a[i] / r)?left.get(a[i] / r):0;
right.set(a[i],right.get(a[i])-1);
c2 = right.has(a[i] * r)?right.get(a[i] * r):0;
ans += c1 * c2;
if (left.has(a[i])){
left.set(a[i],left.get(a[i])+1);
}
else left.set(a[i],1);
}
return ans;
}
let a = [ 1, 2, 6, 2, 3, 6, 9, 18, 3, 9 ];
let n = a.length;
let r = 3;
document.write(subsequences(a, n, r));
</script>
|
Time Complexity: O(n), where n represents the size of the given array.
Auxiliary Space: O(n), where n represents the size of the given array.
The above solution does not handle the case when r is 1 : For example, for input = {1,1,1,1,1}, there are 10 possible for G.P. subsequences of length 3, which can be calculated by using 5C3. Such a procedure should be implemented for all cases where r = 1. Below is the modified code to handle this.
C++
#include <bits/stdc++.h>
using namespace std;
int binomialCoeff( int n, int k) {
int C[k + 1];
memset (C, 0, sizeof (C));
C[0] = 1;
for ( int i = 1; i <= n; i++) {
for ( int j = min(i, k); j > 0; j--)
C[j] = C[j] + C[j - 1];
}
return C[k];
}
long long subsequences( int a[], int n, int r)
{
unordered_map< int , int > left, right;
long long ans = 0;
for ( int i = 0; i < n; i++)
right[a[i]]++;
if (r == 1){
for ( auto i : right) {
ans += binomialCoeff(i.second, 3);
}
return ans;
}
for ( int i = 0; i < n; i++) {
long long c1 = 0, c2 = 0;
if (a[i] % r == 0)
c1 = left[a[i] / r];
right[a[i]]--;
c2 = right[a[i] * r];
ans += c1 * c2;
left[a[i]]++;
}
return ans;
}
int main()
{
int a[] = { 1, 2, 6, 2, 3, 6, 9, 18, 3, 9 };
int n = sizeof (a) / sizeof (a[0]);
int r = 3;
cout << subsequences(a, n, r);
return 0;
}
|
Java
import java.util.*;
class GFG{
static int binomialCoeff( int n, int k)
{
int []C = new int [k + 1 ];
C[ 0 ] = 1 ;
for ( int i = 1 ; i <= n; i++)
{
for ( int j = Math.min(i, k); j > 0 ; j--)
C[j] = C[j] + C[j - 1 ];
}
return C[k];
}
static long subsequences( int a[], int n, int r)
{
HashMap<Integer, Integer> left = new HashMap<>();
HashMap<Integer, Integer> right = new HashMap<>();
long ans = 0 ;
for ( int i = 0 ; i < n; i++)
if (right.containsKey(a[i]))
{
right.put(a[i], right.get(a[i]) + 1 );
}
else
{
right.put(a[i], 1 );
}
if (r == 1 )
{
for (Map.Entry<Integer, Integer> i : right.entrySet())
{
ans += binomialCoeff(i.getValue(), 3 );
}
return ans;
}
for ( int i = 0 ; i < n; i++)
{
long c1 = 0 , c2 = 0 ;
if (a[i] % r == 0 )
if (left.containsKey(a[i] / r))
c1 = left.get(a[i] / r);
if (right.containsKey(a[i]))
{
right.put(a[i], right.get(a[i]) - 1 );
}
else
{
right.put(a[i], - 1 );
}
if (right.containsKey(a[i] * r))
c2 = right.get(a[i] * r);
ans += c1 * c2;
if (left.containsKey(a[i]))
{
left.put(a[i], left.get(a[i]) + 1 );
}
else
{
left.put(a[i], 1 );
}
}
return ans;
}
public static void main(String[] args)
{
int a[] = { 1 , 2 , 6 , 2 , 3 ,
6 , 9 , 18 , 3 , 9 };
int n = a.length;
int r = 3 ;
System.out.print(subsequences(a, n, r));
}
}
|
Python3
from collections import defaultdict
def binomialCoeff(n, k):
C = [ 0 ] * (k + 1 )
C[ 0 ] = 1
for i in range ( 1 , n + 1 ):
for j in range ( min (i, k), - 1 , - 1 ):
C[j] = C[j] + C[j - 1 ]
return C[k]
def subsequences(a, n, r):
left = defaultdict ( int )
right = defaultdict ( int )
ans = 0
for i in range (n):
right[a[i]] + = 1
if (r = = 1 ):
for i in right:
ans + = binomialCoeff(right[i], 3 )
return ans
for i in range (n):
c1 = 0
c2 = 0 ;
if (a[i] % r = = 0 ):
c1 = left[a[i] / / r]
right[a[i]] - = 1
c2 = right[a[i] * r]
ans + = c1 * c2
left[a[i]] + = 1
return ans
if __name__ = = "__main__" :
a = [ 1 , 2 , 6 , 2 , 3 ,
6 , 9 , 18 , 3 , 9 ]
n = len (a)
r = 3
print ( subsequences(a, n, r))
|
C#
using System;
using System.Collections.Generic;
class GFG{
static int binomialCoeff( int n,
int k)
{
int []C = new int [k + 1];
C[0] = 1;
for ( int i = 1; i <= n; i++)
{
for ( int j = Math.Min(i, k);
j > 0; j--)
C[j] = C[j] + C[j - 1];
}
return C[k];
}
static long subsequences( int []a,
int n, int r)
{
Dictionary< int ,
int > left =
new Dictionary< int ,
int >();
Dictionary< int ,
int > right =
new Dictionary< int ,
int >();
long ans = 0;
for ( int i = 0; i < n; i++)
if (right.ContainsKey(a[i]))
{
right[a[i]]++;
}
else
{
right.Add(a[i], 1);
}
if (r == 1)
{
foreach (KeyValuePair< int ,
int > i in right)
{
ans += binomialCoeff(i.Value, 3);
}
return ans;
}
for ( int i = 0; i < n; i++)
{
long c1 = 0, c2 = 0;
if (a[i] % r == 0)
if (left.ContainsKey(a[i] / r))
c1 = left[a[i] / r];
if (right.ContainsKey(a[i]))
{
right[a[i]]--;
}
else
{
right.Add(a[i], -1);
}
if (right.ContainsKey(a[i] * r))
c2 = right[a[i] * r];
ans += c1 * c2;
if (left.ContainsKey(a[i]))
{
left[a[i]]++;
}
else
{
left.Add(a[i], 1);
}
}
return ans;
}
public static void Main(String[] args)
{
int []a = {1, 2, 6, 2, 3,
6, 9, 18, 3, 9};
int n = a.GetLength(0);
int r = 3;
Console.Write(subsequences(a, n, r));
}
}
|
Javascript
function binomialCoeff(n, k)
{
let C = new Array(k + 1);
C[0] = 1;
for ( var i = 1; i <= n; i++)
{
for ( var j = Math.min(i, k); j > 0; j--)
C[j] = C[j] + C[j - 1];
}
return C[k];
}
function subsequences(a, n, r)
{
let left = {};
let right = {};
let ans = 0;
for ( var i = 0; i < n; i++)
if (right.hasOwnProperty(a[i]))
{
right[a[i]] = right[a[i]] + 1;
}
else
{
right[a[i]] = 1;
}
if (r == 1)
{
for ( var i of right)
{
ans += binomialCoeff(right[i], 3);
}
return ans;
}
for ( var i = 0; i < n; i++)
{
let c1 = 0, c2 = 0;
if (a[i] % r == 0)
if (left.hasOwnProperty(Math.floor(a[i] / r)))
c1 = left[(Math.floor(a[i] / r))];
if (right.hasOwnProperty(a[i]))
{
right[a[i]] = right[a[i]] - 1;
}
else
{
right[a[i]] = -1;
}
if (right.hasOwnProperty(a[i] * r))
c2 = right[a[i] * r];
ans += c1 * c2;
if (left.hasOwnProperty(a[i]))
{
left[a[i]] = left[a[i]] + 1;
}
else
{
left[a[i]] = 1;
}
}
return ans;
}
let a = [ 1, 2, 6, 2, 3, 6, 9, 18, 3, 9 ];
let n = a.length;
let r = 3;
console.log(subsequences(a, n, r));
|
Time Complexity: O(n), where n represents the size of the given array.
Auxiliary Space: O(n), where n represents the size of the given array.
Last Updated :
24 Mar, 2023
Like Article
Save Article
Share your thoughts in the comments
Please Login to comment...