Given an array arr[] of positive integers of size N, the task is to find the maximum product of bitonic subsequence of size 3.
Bitonic Subsequence: subsequence in which elements are first in the increasing order and then decreasing order. Elements in the subsequence are follow this order arr[i] < arr[j] > arr[k] for i < j < k where i, j, k are the index of the given array.
Note: If no such element is found then print -1.
Examples:
Input: arr[] = {1, 8, 3, 7, 5, 6, 7}
Output: 126
Explanation:
Bitonic subsequences of size 3 are
{1, 8, 3}, {1, 8, 7}, {1, 8, 5}, {1, 8, 6}, {1, 7, 6}, {3, 7, 6}, {1, 7, 5}, {3, 7, 5}.
Hence the maximum product of bitonic subsequence is 3*7*6 = 126
Input: arr[] = {1, 8, 3, 7}
Output: 56
Explanation:
Bitonic subsequences of size 3 are
{1, 8, 3}, {1, 8, 7}, {1, 7, 3}.
Hence the maximum product of bitonic subsequence is 1*8*7 = 56
Naive Approach:A simple solution is to find the product of all the bitonic subsequences of size 3 and take the maximum among them.
Algorithm:
- Initialize ans to -1, such that if there is no such subsequence then the output will be -1.
- Iterate over the Array with three nested loops with loop variables as i, j, and k for choosing three elements of the array.
- Check if arr[j] > arr[i] and arr[j] > arr[k] then update the ans with the maximum value between ans and arr[i] * arr[j] * arr[k].
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
int maxProduct( int arr[], int n){
int ans = -1;
for ( int i = 0; i < n - 2; i++) {
for ( int j = i + 1; j < n - 1; j++) {
for ( int k = j + 1; k < n; k++) {
if (arr[i] < arr[j] &&
arr[j] > arr[k])
ans = max(
ans, arr[i] * arr[j] * arr[k]
);
}
}
}
return ans;
}
int main()
{
int arr[] = { 1, 8, 3, 7 };
int n = sizeof (arr) / sizeof (arr[0]);
cout << maxProduct(arr, n) << endl;
}
|
Java
import java.util.*;
class GFG{
static int maxProduct( int arr[], int n){
int ans = - 1 ;
for ( int i = 0 ; i < n - 2 ; i++) {
for ( int j = i + 1 ; j < n - 1 ; j++) {
for ( int k = j + 1 ; k < n; k++) {
if (arr[i] < arr[j] &&
arr[j] > arr[k])
ans = Math.max(
ans, arr[i] * arr[j] * arr[k]
);
}
}
}
return ans;
}
public static void main(String[] args)
{
int arr[] = { 1 , 8 , 3 , 7 };
int n = arr.length;
System.out.print(maxProduct(arr, n) + "\n" );
}
}
|
Python3
def maxProduct(arr, n):
ans = - 1
for i in range (n - 2 ):
for j in range (i + 1 , n - 1 ):
for k in range (j + 1 , n):
if (arr[i] < arr[j] and arr[j] > arr[k]):
ans = max (ans, arr[i] * arr[j] * arr[k])
return ans
if __name__ = = '__main__' :
arr = [ 1 , 8 , 3 , 7 ]
n = len (arr)
print (maxProduct(arr, n))
|
C#
using System;
class GFG {
static int maxProduct( int [] arr, int n)
{
int ans = -1;
for ( int i = 0; i < n - 2; i++) {
for ( int j = i + 1; j < n - 1; j++) {
for ( int k = j + 1; k < n; k++) {
if (arr[i] < arr[j] &&
arr[j] > arr[k])
ans = Math.Max(ans, arr[i] * arr[j] * arr[k]
);
}
}
}
return ans;
}
static void Main()
{
int [] arr = new int [] { 1, 8, 3, 7 };
int n = arr.Length;
Console.Write(maxProduct(arr, n));
}
}
|
Javascript
<script>
function maxProduct(arr,n){
let ans = -1;
for (let i = 0; i < n - 2; i++) {
for (let j = i + 1; j < n - 1; j++) {
for (let k = j + 1; k < n; k++) {
if (arr[i] < arr[j] &&
arr[j] > arr[k])
ans = Math.max(
ans, arr[i] * arr[j] * arr[k]
);
}
}
}
return ans;
}
let arr = [ 1, 8, 3, 7 ];
let n = arr.length;
document.write(maxProduct(arr, n) + "<br>" );
</script>
|
Performance Analysis:
- Time Complexity: As in the above approach, there is three nested loops to find the maximum product of the bitonic subsequence of size 3, hence the Time Complexity will be O(N3).
- Auxiliary Space: As in the above approach, there is no extra space used, hence the auxiliary space will be O(1).
Efficient approach: The idea is to find the largest value on the left side and right side of each index which are smaller than the element present at the current index, to do this use a Self Balancing BST and then for every element find the maximum product that can be formed and take the maximum out of those products.
Self-Balancing BST is implemented as set in C++ and TreeSet in Java.
Algorithm:
- Declare a self-balancing BST (say s).
- Declare two new arrays left[] and right[] to store the lower bound for arr[i] in left of that element in left[i] and lower bound of arr[i] in right of that element in right[i].
- Run a loop from 0 to length – 1 to find the lower bound of arr[i] is left of that element and store it in the left[i].
- Run a loop from length -1 to 0 to find the lower bound of arr[i] in the right of that element and store it in the right[i].
- Run a loop from 0 to length – 1 to find the bitonic subsequence that can be formed using that element to get the maximum product using the left[] and right[] array. That is for every element maximum product bitonic subsequence that can be formed is left[i] * right[i] * arr[i].
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
int maxProduct( int arr[], int n){
set< int > s;
set< int >::iterator it;
int Left[n];
int Right[n];
for ( int i = 0; i < n; i++) {
s.insert(arr[i]);
it = s.lower_bound(arr[i]);
if (it != s.begin()) {
it--;
Left[i] = *it;
}
else {
Left[i] = -1;
}
}
s.clear();
for ( int i = n - 1; i >= 0; i--) {
s.insert(arr[i]);
it = s.lower_bound(arr[i]);
if (it != s.begin()) {
it--;
Right[i] = *it;
}
else {
Right[i] = -1;
}
}
int ans = -1;
for ( int i = 0; i < n; i++) {
if (Left[i] > 0 and Right[i] > 0)
ans = max(ans, arr[i] * Left[i] * Right[i]);
}
if (ans < 0) {
return -1;
}
else {
return ans;
}
}
int main()
{
int arr[] = { 1, 8, 3, 7, 5, 6, 7 };
int n = sizeof (arr) / sizeof (arr[0]);
cout << maxProduct(arr, n);
}
|
Java
import java.util.*;
import java.lang.System;
class GFG{
public static int maxProduct( int arr[], int n)
{
TreeSet<Integer> ts = new TreeSet<Integer>();
int Left[] = new int [n];
int Right[] = new int [n];
for ( int i = 0 ; i < n; i++)
{
ts.add(arr[i]);
if (ts.lower(arr[i]) == null )
Left[i] = - 1 ;
else
Left[i] = ts.lower(arr[i]);
}
ts.clear();
for ( int i = n- 1 ; i >= 0 ; i--)
{
ts.add(arr[i]);
if (ts.lower(arr[i]) == null )
Right[i] = - 1 ;
else
Right[i] = ts.lower(arr[i]);
}
int ans = 0 ;
for ( int i = 0 ; i < n; i++)
{
if (Left[i] != - 1 && Right[i] != - 1 )
ans = Math.max(ans, Left[i] * arr[i] * Right[i]);
}
return ans;
}
public static void main(String args[])
{
int arr[] = { 1 , 8 , 3 , 7 , 5 , 6 , 7 };
int n = arr.length;
int maximum_product = maxProduct(arr,n);
System.out.println(maximum_product);
}
}
|
Python3
import sys
from bisect import bisect_left
def maxProduct(arr, n):
Left = [ - 1 for i in range (n)]
Right = [ - 1 for i in range (n)]
for i in range ( 1 , n):
max_value = - sys.maxsize
for j in range (i):
if arr[j] < arr[i]:
max_value = max (max_value, arr[j])
Left[i] = max_value
for i in range (n - 2 , - 1 , - 1 ):
max_value = - sys.maxsize
for j in range (i + 1 , n):
if arr[j] < arr[i]:
max_value = max (max_value, arr[j])
Right[i] = max_value
ans = - sys.maxsize
for i in range (n):
if Left[i] > 0 and Right[i] > 0 :
ans = max (ans, arr[i] * Left[i] * Right[i])
if ans = = - sys.maxsize:
return - 1
else :
return ans
arr = [ 1 , 8 , 3 , 7 , 5 , 6 , 7 ]
n = len (arr)
print (maxProduct(arr, n))
|
Javascript
function lower_bound(s, x){
let arr = Array.from(s);
arr.sort();
let l = 0;
let h = arr.length - 1;
while (l <= h){
let m = Math.floor((l + h)/2);
if (arr[m] > x) h = m - 1;
else if (arr[m] < x) l = m + 1;
else {
return m;
}
}
return l;
}
function maxProduct(arr, n){
let s = new Set();
let Left = new Array(n);
let Right = new Array(n);
for (let i = 0; i < n; i++) {
s.add(arr[i]);
it = lower_bound(s, arr[i]);
let temp = Array.from(s);
temp.sort();
if (it != 0) {
Left[i] = temp[it-1];
}
else {
Left[i] = -1;
}
}
s.clear();
for (let i = n - 1; i >= 0; i--) {
s.add(arr[i]);
it = lower_bound(s, arr[i]);
let temp = Array.from(s);
temp.sort();
if (it != 0) {
Right[i] = temp[it-1];
}
else {
Right[i] = -1;
}
}
let ans = -1;
for (let i = 0; i < n; i++) {
if (Left[i] > 0 && Right[i] > 0)
ans = Math.max(ans, arr[i] * Left[i] * Right[i]);
}
if (ans < 0) {
return -1;
}
else {
return ans;
}
}
let arr = [ 1, 8, 3, 7, 5, 6, 7 ];
let n = arr.length;
console.log(maxProduct(arr, n));
|
C#
using System;
class GFG {
static int maxProduct( int [] arr, int n)
{
int [] Left = new int [n];
for ( int i = 0; i < n; i++)
Left[i] = -1;
int [] Right = new int [n];
for ( int i = 0; i < n; i++)
Right[i] = -1;
for ( int i = 1; i < n; i++) {
int max_value = int .MinValue;
for ( int j = 0; j < i; j++) {
if (arr[j] < arr[i])
max_value = Math.Max(max_value, arr[j]);
}
Left[i] = max_value;
}
for ( int i = n - 2; i >= 0; i--) {
int max_value = int .MinValue;
for ( int j = i + 1; j < n; j++) {
if (arr[j] < arr[i])
max_value = Math.Max(max_value, arr[j]);
}
Right[i] = max_value;
}
int ans = int .MinValue;
for ( int i = 0; i < n; i++) {
if (Left[i] > 0 && Right[i] > 0)
ans = Math.Max(ans,
arr[i] * Left[i] * Right[i]);
}
if (ans == int .MinValue)
return -1;
else
return ans;
}
public static void Main()
{
int [] arr = { 1, 8, 3, 7, 5, 6, 7 };
int n = arr.Length;
Console.WriteLine(maxProduct(arr, n));
}
}
|
Performance Analysis:
- Time Complexity: O(NlogN).
- Auxiliary Space: O(N).