Minimal product subsequence where adjacent elements are separated by a maximum distance of K
Given an array arr[] and an integer K, the task is to find out the minimum product of a subsequence where adjacent elements of the subsequence are separated by a maximum distance of K.
Note: The subsequence should include the first and the last element of the array.
Examples:
Input: arr[] = { 1, 2, 3, 4 }, K = 2
Output: 8
The first element in the subsequence is 1. From 1, we can move to either 2 or 3 (since K = 2). We can move to 3 and then to 4 to have a product of 12. However, we can also move to 2 and then to 4 to have a product of 8. Minimal product subsequence = { 1, 2, 4 }
Input: arr[] = { 2, 3 }, K = 2
Output: 6
Naive Approach: A naive approach is to generate all subsequences of the array and maintain a difference of indices between the adjacent elements and find the minimal product subsequence.
Efficient Approach: An efficient approach is to use dynamic programming. Let dp[i] denote the minimum product of elements till index ‘i’ including arr[i] who are separated by a maximum distance of K. Then dp[i] can be formulated as follows:
dp[i] = arr[i] * min{dp[j]} where j < i and 1 <= i - j <= K.
To calculate dp[i], a window of size K can be maintained and traversed to find the minimum of dp[j] which can then be multiplied to arr[i]. However, this will result in an O(N*K) solution.
To optimize the solution further, values of the product can be stored in an STL set and the minimum value of the product can then be found out in O(log n) time. Since storing products can be a cumbersome task since the product can easily exceed 1018, therefore we will store log values of products since log is a monotonic function and minimization of log values will automatically imply minimization of products.
Below is the implementation of the above approach:
CPP
#include <bits/stdc++.h>
#define mp make_pair
#define ll long long
using namespace std;
const int mod = 1000000007;
const int MAX = 100005;
int minimumProductSubsequence( int * arr, int n, int k)
{
multiset<pair< double , int > > s;
ll dp[MAX];
double p[MAX];
dp[0] = arr[0];
p[0] = log (arr[0]);
s.insert(mp(p[0], dp[0]));
for ( int i = 1; i < k; i++) {
double l = (s.begin())->first;
ll min = (s.begin())->second;
p[i] = log (arr[i]) + l;
dp[i] = (arr[i] * min) % mod;
s.insert(mp(p[i], dp[i]));
}
for ( int i = k; i < n; i++) {
double l = (s.begin())->first;
ll min = (s.begin())->second;
p[i] = log (arr[i]) + l;
dp[i] = (arr[i] * min) % mod;
multiset<pair< double , int > >::iterator it;
it = s.find(mp(p[i - k], dp[i - k]));
s.erase(it);
s.insert(mp(p[i], dp[i]));
}
return dp[n - 1];
}
int main()
{
int arr[] = { 1, 2, 3, 4 };
int n = sizeof (arr) / sizeof (arr[0]);
int k = 2;
cout << minimumProductSubsequence(arr, n, k);
return 0;
}
|
Java
import java.io.*;
import java.util.*;
class GFG {
static class Pair {
double x;
int y;
Pair( double x, int y)
{
this .x = x;
this .y = y;
}
}
static int mod = 1000000007 ;
static int MAX = 100005 ;
static int minimumProductSubsequence( int [] arr, int n,
int k)
{
TreeSet<Pair> s
= new TreeSet<>( new Comparator<Pair>() {
public int compare(Pair a, Pair b)
{
return Double.compare(a.x, b.x);
}
});
int [] dp = new int [MAX];
double [] p = new double [MAX];
dp[ 0 ] = arr[ 0 ];
p[ 0 ] = Math.log(arr[ 0 ]);
s.add( new Pair(p[ 0 ], dp[ 0 ]));
for ( int i = 1 ; i < k; i++) {
double l = s.first().x;
int min = s.first().y;
p[i] = Math.log(arr[i]) + l;
dp[i] = ( int )((arr[i] * min) % mod);
s.add( new Pair(p[i], dp[i]));
}
for ( int i = k; i < n; i++) {
double l = s.first().x;
int min = s.first().y;
p[i] = Math.log(arr[i]) + l;
dp[i] = ( int )((arr[i] * min) % mod);
s.remove( new Pair(p[i - k], dp[i - k]));
s.add( new Pair(p[i], dp[i]));
}
return ( int )dp[n - 1 ];
}
public static void main(String[] args)
{
int [] arr = { 1 , 2 , 3 , 4 };
int n = arr.length;
int k = 2 ;
System.out.println(
minimumProductSubsequence(arr, n, k));
}
}
|
Python3
import math
mod = 1000000007 ;
MAX = 100005 ;
def minimumProductSubsequence(arr, n, k):
s = []
dp = [ 0 for i in range ( MAX )];
p = [ 0.0 for i in range ( MAX )];
dp[ 0 ] = arr[ 0 ];
p[ 0 ] = math.log(arr[ 0 ]);
s.append([p[ 0 ], dp[ 0 ]]);
s.sort()
for i in range ( 1 , k):
l = s[ 0 ][ 0 ]
min = s[ 0 ][ 1 ]
p[i] = math.log(arr[i]) + l;
dp[i] = (arr[i] * min ) % mod;
s.append([p[i], dp[i]]);
s.sort()
for i in range (k, n):
l = s[ 0 ][ 0 ]
min = s[ 0 ][ 1 ]
p[i] = math.log(arr[i]) + l;
dp[i] = (arr[i] * min ) % mod;
if [p[i - k], dp[i - k]] in s:
s.pop(s.index([p[i - k], dp[i - k]]))
s.append([p[i], dp[i]]);
s.sort()
return dp[n - 1 ];
if __name__ = = '__main__' :
arr = [ 1 , 2 , 3 , 4 ]
n = len (arr)
k = 2 ;
print (minimumProductSubsequence(arr, n, k))
|
C#
using System;
using System.Collections.Generic;
class GFG {
static int mod = 1000000007;
static int MAX = 100005;
public static int minimumProductSubsequence( int [] arr, int n, int k) {
SortedSet<Tuple< double , long >> s = new SortedSet<Tuple< double , long >>(
Comparer<Tuple< double , long >>.Create((a, b) => a.Item1.CompareTo(b.Item1))
);
long [] dp= new long [MAX];
double [] p= new double [MAX];
dp[0] = arr[0];
p[0] = Math.Log(arr[0]);
s.Add(Tuple.Create(p[0], dp[0]));
for ( int i = 1; i < k; i++) {
double l = s.Min.Item1;
long min = s.Min.Item2;
p[i] = Math.Log(arr[i]) + l;
dp[i] = (arr[i] * min) % mod;
s.Add(Tuple.Create(p[i], dp[i]));
}
for ( int i = k; i < n; i++) {
double l = s.Min.Item1;
long min = s.Min.Item2;
p[i] = Math.Log(arr[i]) + l;
dp[i] = (arr[i] * min) % mod;
s.Remove(Tuple.Create(p[i - k], dp[i - k]));
s.Add(Tuple.Create(p[i], dp[i]));
}
return ( int ) dp[n - 1];
}
public static void Main( string [] args) {
int [] arr = { 1, 2, 3, 4 };
int n = arr.Length;
int k = 2;
Console.WriteLine(minimumProductSubsequence(arr, n, k));
}
}
|
Javascript
let mod = 1000000007;
let MAX = 100005;
function minimumProductSubsequence(arr, n, k)
{
let s = []
let dp = new Array(MAX).fill(0)
let p = new Array(MAX).fill(0.0)
dp[0] = arr[0];
p[0] = Math.log(arr[0]);
s.push([p[0], dp[0]]);
s.sort()
for ( var i = 1; i < k; i++)
{
let l = s[0][0]
let min = s[0][1]
p[i] = Math.log(arr[i]) + l;
dp[i] = (arr[i] * min) % mod;
s.push([p[i], dp[i]]);
s.sort((a, b) => (a[0] != b[0]) ? (a[0] < b[0]) : (a[1] < b[1]))
}
for ( var i = k; i < n; i++)
{
let l = s[0][0]
let min = s[0][1]
p[i] = Math.log(arr[i]) + l;
dp[i] = (arr[i] * min) % mod;
if (s.indexOf([p[i - k], dp[i - k]] != -1))
s.splice(s.indexOf([p[i - k], dp[i - k]]), 1)
s.push([p[i], dp[i]]);
s.sort((a, b) => (a[0] != b[0]) ? (a[0] > b[0]) : (a[1] > b[1]))
}
return dp[n - 1];
}
let arr = [ 1, 2, 3, 4 ]
let n = arr.length
let k = 2;
console.log(minimumProductSubsequence(arr, n, k))
|
Time Complexity: O(N* log(N))
Auxiliary Space: O(N), since N extra space has been taken.
Last Updated :
06 Feb, 2023
Like Article
Save Article
Share your thoughts in the comments
Please Login to comment...