Open In App

Length of longest strict bitonic subsequence

Improve
Improve
Like Article
Like
Save
Share
Report

Given an array arr[] containing n integers. The problem is to find the length of the longest strict bitonic subsequence. A subsequence is called strict bitonic if it is first increasing and then decreasing with the condition that in both the increasing and decreasing parts the absolute difference between adjacents is 1 only. A sequence, sorted in increasing order is considered Bitonic with the decreasing part as empty. Similarly, decreasing order sequence is considered Bitonic with the increasing part as empty.

Examples: 

Input : arr[] = {1, 5, 2, 3, 4, 5, 3, 2}
Output : 6
The Longest Strict Bitonic Subsequence is:
{1, 2, 3, 4, 3, 2}.

Input : arr[] = {1, 2, 5, 3, 6, 7, 4, 6, 5}
Output : 5

Method 1: The problem could be solved using the concept of finding the longest bitonic subsequence. The only condition that needs to be maintained is that the adjacents should have a difference of 1 only. It has a time complexity of O(n2).

  • We need to construct two arrays lis[] and lds[] using the Dynamic Programming solution of the LIS problem.
  • lis[i] stores the length of the Longest Increasing subsequence ending with arr[i].
  • lds[i] stores the length of the longest Decreasing subsequence starting from arr[i].
  • Finally, we need to return the max value of lis[i] + lds[i] – 1 where i is from 0 to n-1.

Below is the implementation of the above approach:

C++




/*Length of longest strict bitonic subsequence using Dynamic Programming */
#include <stdio.h>
#include <stdlib.h>
 
/* lbs() returns the length of the Longest Bitonic
   Subsequence in arr[] of size n. The function mainly
   creates two temporary arrays lis[] and lds[] and returns
   the maximum lis[i] + lds[i] - 1.
 
        lis[i] ==> Longest Increasing subsequence ending
   with arr[i] lds[i] ==> Longest decreasing subsequence
   starting with arr[i]
*/
int lbs(int arr[], int n)
{
    int i, j;
 
    /* Allocate memory for LIS[] and initialize LIS values
       as 1 for all indexes */
    int* lis = new int[n];
    for (i = 0; i < n; i++)
        lis[i] = 1;
 
    /* Compute LIS values from left to right */
    for (i = 1; i < n; i++)
        for (j = 0; j < i; j++)
            if (arr[i] > arr[j] && abs(arr[i] - arr[j] == 1)
                && lis[i] < lis[j] + 1)
                lis[i] = lis[j] + 1;
 
    /* Allocate memory for lds and initialize LDS values for
            all indexes */
    int* lds = new int[n];
    for (i = 0; i < n; i++)
        lds[i] = 1;
 
    /* Compute LDS values from right to left */
    for (i = n - 2; i >= 0; i--)
        for (j = n - 1; j > i; j--)
            if (arr[i] > arr[j] && abs(arr[i] - arr[j] == 1)
                && lds[i] < lds[j] + 1)
                lds[i] = lds[j] + 1;
 
    /* Return the maximum value of lis[i] + lds[i] - 1*/
    int max = lis[0] + lds[0] - 1;
    for (i = 1; i < n; i++)
        if (lis[i] + lds[i] - 1 > max)
            max = lis[i] + lds[i] - 1;
    return max;
}
 
/* Driver program to test above function */
int main()
{
    int arr[] = { 1, 5, 2, 3, 4, 5, 3, 2 };
    int n = sizeof(arr) / sizeof(arr[0]);
    printf("Length of LBS is %d\n", lbs(arr, n));
    return 0;
}
 
// This code is contributed by hkdass001


Python3




def lbs(arr):
    n = len(arr)
 
    # Allocate memory for LIS[] and initialize LIS values as 1 for all indexes
    lis = [1] * n
 
    # Compute LIS values from left to right
    for i in range(1, n):
        for j in range(0, i):
            if arr[i] > arr[j] and abs(arr[i] - arr[j]) == 1 and lis[i] < lis[j] + 1:
                lis[i] = lis[j] + 1
 
    # Allocate memory for lds and initialize LDS values for all indexes
    lds = [1] * n
 
    # Compute LDS values from right to left
    for i in range(n - 2, -1, -1):
        for j in range(n - 1, i, -1):
            if arr[i] > arr[j] and abs(arr[i] - arr[j]) == 1 and lds[i] < lds[j] + 1:
                lds[i] = lds[j] + 1
 
    # Return the maximum value of lis[i] + lds[i] - 1
    max_val = lis[0] + lds[0] - 1
    for i in range(1, n):
        max_val = max(max_val, lis[i] + lds[i] - 1)
    return max_val
 
# Driver program to test above function
arr = [1, 5, 2, 3, 4, 5, 3, 2]
print("Length of LBS is", lbs(arr))
 
# This code is contributed by vikramshirsath177


C#




/*Length of longest strict bitonic subsequence using Dynamic Programming */
using System;
using System.Collections.Generic;
 
/* lbs() returns the length of the Longest Bitonic
   Subsequence in arr[] of size n. The function mainly
   creates two temporary arrays lis[] and lds[] and returns
   the maximum lis[i] + lds[i] - 1.
 
        lis[i] ==> Longest Increasing subsequence ending
   with arr[i] lds[i] ==> Longest decreasing subsequence
   starting with arr[i]
*/
class Gfg
{
    static int lbs(int[] arr, int n)
    {
        int i, j;
     
        /* Allocate memory for LIS[] and initialize LIS values
           as 1 for all indexes */
        int[] lis = new int[n];
        for (i = 0; i < n; i++)
            lis[i] = 1;
     
        /* Compute LIS values from left to right */
        for (i = 1; i < n; i++)
            for (j = 0; j < i; j++)
                if (arr[i] > arr[j] && Math.Abs(arr[i] - arr[j]) == 1 && lis[i] < lis[j] + 1)
                    lis[i] = lis[j] + 1;
     
        /* Allocate memory for lds and initialize LDS values for
                all indexes */
        int[] lds = new int[n];
        for (i = 0; i < n; i++)
            lds[i] = 1;
     
        /* Compute LDS values from right to left */
        for (i = n - 2; i >= 0; i--)
            for (j = n - 1; j > i; j--)
                if (arr[i] > arr[j] && Math.Abs(arr[i] - arr[j]) == 1 && lds[i] < lds[j] + 1)
                    lds[i] = lds[j] + 1;
     
        /* Return the maximum value of lis[i] + lds[i] - 1*/
        int max = lis[0] + lds[0] - 1;
        for (i = 1; i < n; i++)
            if (lis[i] + lds[i] - 1 > max)
                max = lis[i] + lds[i] - 1;
        return max;
    }
     
    /* Driver program to test above function */
    public static void Main(string[] args)
    {
        int[] arr = { 1, 5, 2, 3, 4, 5, 3, 2 };
        int n = arr.Length;
        Console.Write("Length of LBS is "+ lbs(arr, n));
    }
}


Javascript




/*Length of longest strict bitonic subsequence using Dynamic Programming */
 
/* lbs() returns the length of the Longest Bitonic
   Subsequence in arr[] of size n. The function mainly
   creates two temporary arrays lis[] and lds[] and returns
   the maximum lis[i] + lds[i] - 1.
 
        lis[i] ==> Longest Increasing subsequence ending
   with arr[i] lds[i] ==> Longest decreasing subsequence
   starting with arr[i]
*/
function lbs(arr, n)
{
    let i, j;
 
    /* Allocate memory for LIS[] and initialize LIS values
       as 1 for all indexes */
    let lis = new Array(n);
    for (i = 0; i < n; i++)
        lis[i] = 1;
 
    /* Compute LIS values from left to right */
    for (i = 1; i < n; i++)
        for (j = 0; j < i; j++)
            if (arr[i] > arr[j] && Math.abs(arr[i] - arr[j] == 1)
                && lis[i] < lis[j] + 1)
                lis[i] = lis[j] + 1;
 
    /* Allocate memory for lds and initialize LDS values for
            all indexes */
    let lds = new Array(n);
    for (i = 0; i < n; i++)
        lds[i] = 1;
 
    /* Compute LDS values from right to left */
    for (i = n - 2; i >= 0; i--)
        for (j = n - 1; j > i; j--)
            if (arr[i] > arr[j] && Math.abs(arr[i] - arr[j] == 1)
                && lds[i] < lds[j] + 1)
                lds[i] = lds[j] + 1;
 
    /* Return the maximum value of lis[i] + lds[i] - 1*/
    let max = lis[0] + lds[0] - 1;
    for (i = 1; i < n; i++)
        if (lis[i] + lds[i] - 1 > max)
            max = lis[i] + lds[i] - 1;
    return max;
}
 
/* Driver program to test above function */
let arr = [ 1, 5, 2, 3, 4, 5, 3, 2 ];
let n = arr.length;
console.log("Length of LBS is ", lbs(arr, n));
 
// This code is contributed by poojaagarwal2.


Java




/*Length of longest strict bitonic subsequence using Dynamic Programming */
 
import java.util.*;
import java.lang.Math;
 
/* lbs() returns the length of the Longest Bitonic
   Subsequence in arr[] of size n. The function mainly
   creates two temporary arrays lis[] and lds[] and returns
   the maximum lis[i] + lds[i] - 1.
 
        lis[i] ==> Longest Increasing subsequence ending
   with arr[i] lds[i] ==> Longest decreasing subsequence
   starting with arr[i]
*/
class GfG
{
    static int lbs(int arr[], int n)
    {
        int i, j;
     
        /* Allocate memory for LIS[] and initialize LIS values
           as 1 for all indexes */
        int lis[] = new int[n];
        for (i = 0; i < n; i++)
            lis[i] = 1;
     
        /* Compute LIS values from left to right */
        for (i = 1; i < n; i++)
            for (j = 0; j < i; j++)
                if (arr[i] > arr[j] && Math.abs(arr[i] - arr[j]) == 1 && lis[i] < lis[j] + 1)
                    lis[i] = lis[j] + 1;
     
        /* Allocate memory for lds and initialize LDS values for
                all indexes */
        int lds[] = new int[n];
        for (i = 0; i < n; i++)
            lds[i] = 1;
     
        /* Compute LDS values from right to left */
        for (i = n - 2; i >= 0; i--)
            for (j = n - 1; j > i; j--)
                if (arr[i] > arr[j] && Math.abs(arr[i] - arr[j]) == 1 && lds[i] < lds[j] + 1)
                    lds[i] = lds[j] + 1;
     
        /* Return the maximum value of lis[i] + lds[i] - 1*/
        int max = lis[0] + lds[0] - 1;
        for (i = 1; i < n; i++)
            if (lis[i] + lds[i] - 1 > max)
                max = lis[i] + lds[i] - 1;
        return max;
    }
     
    /* Driver program to test above function */
    public static void main(String[] args)
    {
        int arr[] = { 1, 5, 2, 3, 4, 5, 3, 2 };
        int n = arr.length;
        System.out.println("Length of LBS is "+ lbs(arr, n));
    }
}


Output

Length of LBS is 6

Time Complexity: O(n*n)
Auxiliary Space: O(n)

Method 2 (Efficient Approach): 

The idea is to create two hash maps inc and dcr having tuples in the form (ele, len), where len denotes the length of the longest increasing subsequence ending with the element ele in map inc and length of the longest decreasing subsequence starting with element ele in map dcr respectively. Also create two arrays len_inc[] and len_dcr[] where len_inc[i] represents the length of the largest increasing subsequence ending with element arr[i] and len_dcr[i] represents the length of the largest decreasing subsequence starting with element arr[i]. Now, for each element arr[i] we can find the length of the value (arr[i]-1) if it exists in the hash table inc. Let this value be v (initially v will be 0)

Now, the length of longest increasing subsequence ending with arr[i] would be v+1. Update this length along with the element arr[i] in the hash table inc and in the array len_inc[] at respective index i. Now, traversing the array from right to left we can similarly fill the hash table dcr and array len_dcr[] for longest decreasing subsequence. Finally, for each element arr[i] we calculate (len_inc[i] + len_dcr[i] – 1) and return the maximum value.

Note: Here increasing and decreasing subsequences only mean that the difference between adjacent elements is 1 only.

Implementation:

C++




// C++ implementation to find length of longest
// strict bitonic subsequence
#include <bits/stdc++.h>
using namespace std;
    
// function to find length of longest
// strict bitonic subsequence
int longLenStrictBitonicSub(int arr[], int n)
{
    // hash table to map the array element with the
    // length of the longest subsequence of which
    // it is a part of and is the last/first element of
    // that subsequence
    unordered_map<int, int> inc, dcr;
     
    // arrays to store the length of increasing and
    // decreasing subsequences which end at them
    // or start from them 
    int len_inc[n], len_dcr[n];
     
    // to store the length of longest strict
    // bitonic subsequence
    int longLen = 0;
     
    // traverse the array elements
    // from left to right
    for (int i=0; i<n; i++)
    {
        // initialize current length
        // for element arr[i] as 0
        int len = 0;
           
        // if 'arr[i]-1' is in 'inc'
        if (inc.find(arr[i]-1) != inc.end())
            len = inc[arr[i]-1];
           
        // update arr[i] subsequence length in 'inc'   
        // and in len_inc[]
        inc[arr[i]] = len_inc[i] = len + 1;
    }
     
    // traverse the array elements
    // from right to left
    for (int i=n-1; i>=0; i--)
    {
        // initialize current length
        // for element arr[i] as 0
        int len = 0;
           
        // if 'arr[i]-1' is in 'dcr'
        if (dcr.find(arr[i]-1) != dcr.end())
            len = dcr[arr[i]-1];
           
        // update arr[i] subsequence length in 'dcr'
        // and in len_dcr[]   
        dcr[arr[i]] = len_dcr[i] = len + 1;
    }
     
    // calculating the length of all the strict
    // bitonic subsequence
    for (int i=0; i<n; i++)
        if (longLen < (len_inc[i] + len_dcr[i] - 1))
            longLen = len_inc[i] + len_dcr[i] - 1;
        
    // required longest length strict
    // bitonic subsequence
    return longLen;       
}
    
// Driver program to test above
int main()
{
    int arr[] = {1, 5, 2, 3, 4, 5, 3, 2};
    int n = sizeof(arr) / sizeof(arr[0]);
    cout << "Longest length strict bitonic subsequence = "
         << longLenStrictBitonicSub(arr, n);
    return 0;


Java




// Java implementation to find length of longest
// strict bitonic subsequence
import java.util.*;
 
class GfG
{
     
// function to find length of longest
// strict bitonic subsequence
static int longLenStrictBitonicSub(int arr[], int n)
{
    // hash table to map the array element with the
    // length of the longest subsequence of which
    // it is a part of and is the last/first element of
    // that subsequence
    HashMap<Integer, Integer> inc = new HashMap<Integer, Integer> ();
    HashMap<Integer, Integer> dcr = new HashMap<Integer, Integer> ();
     
    // arrays to store the length of increasing and
    // decreasing subsequences which end at them
    // or start from them
    int len_inc[] = new int[n];
    int len_dcr[] = new int[n];
     
    // to store the length of longest strict
    // bitonic subsequence
    int longLen = 0;
     
    // traverse the array elements
    // from left to right
    for (int i = 0; i < n; i++)
    {
        // initialize current length
        // for element arr[i] as 0
        int len = 0;
             
        // if 'arr[i]-1' is in 'inc'
        if (inc.containsKey(arr[i] - 1))
            len = inc.get(arr[i] - 1);
             
        // update arr[i] subsequence length in 'inc'    
        // and in len_inc[]
        len_inc[i] = len + 1;
        inc.put(arr[i], len_inc[i]);
    }
     
    // traverse the array elements
    // from right to left
    for (int i = n - 1; i >= 0; i--)
    {
        // initialize current length
        // for element arr[i] as 0
        int len = 0;
             
        // if 'arr[i]-1' is in 'dcr'
        if (dcr.containsKey(arr[i] - 1))
            len = dcr.get(arr[i] - 1);
             
        // update arr[i] subsequence length in 'dcr'
        // and in len_dcr[]
        len_dcr[i] = len + 1;
        dcr.put(arr[i], len_dcr[i]);
    }
     
    // calculating the length of all the strict
    // bitonic subsequence
    for (int i = 0; i < n; i++)
        if (longLen < (len_inc[i] + len_dcr[i] - 1))
            longLen = len_inc[i] + len_dcr[i] - 1;
         
    // required longest length strict
    // bitonic subsequence
    return longLen;    
}
     
// Driver code
public static void main(String[] args)
{
    int arr[] = {1, 5, 2, 3, 4, 5, 3, 2};
    int n = arr.length;
    System.out.println("Longest length strict " +
                            "bitonic subsequence = " +
                            longLenStrictBitonicSub(arr, n));
}
}
 
// This code is contributed by
// prerna saini


Python3




# Python3 implementation to find length of
# longest strict bitonic subsequence
 
# function to find length of longest
# strict bitonic subsequence
def longLenStrictBitonicSub(arr, n):
 
    # hash table to map the array element
    # with the length of the longest subsequence
    # of which it is a part of and is the
    # last/first element of that subsequence
    inc, dcr = dict(), dict()
 
    # arrays to store the length of increasing
    # and decreasing subsequences which end at
    # them or start from them
    len_inc, len_dcr = [0] * n, [0] * n
 
    # to store the length of longest strict
    # bitonic subsequence
    longLen = 0
 
    # traverse the array elements
    # from left to right
    for i in range(n):
 
        # initialize current length
        # for element arr[i] as 0
        len = 0
 
        # if 'arr[i]-1' is in 'inc'
        if inc.get(arr[i] - 1) in inc.values():
            len = inc.get(arr[i] - 1)
         
        # update arr[i] subsequence length in 'inc'    
        # and in len_inc[]
        inc[arr[i]] = len_inc[i] = len + 1
     
    # traverse the array elements
    # from right to left
    for i in range(n - 1, -1, -1):
 
        # initialize current length
        # for element arr[i] as 0
        len = 0
 
        # if 'arr[i]-1' is in 'dcr'
        if dcr.get(arr[i] - 1) in dcr.values():
            len = dcr.get(arr[i] - 1)
         
        # update arr[i] subsequence length 
        # in 'dcr' and in len_dcr[]
        dcr[arr[i]] = len_dcr[i] = len + 1
     
    # calculating the length of
    # all the strict bitonic subsequence
    for i in range(n):
        if longLen < (len_inc[i] + len_dcr[i] - 1):
            longLen = len_inc[i] + len_dcr[i] - 1
     
    # required longest length strict
    # bitonic subsequence
    return longLen
 
# Driver Code
if __name__ == "__main__":
    arr = [1, 5, 2, 3, 4, 5, 3, 2]
    n = len(arr)
    print("Longest length strict bitonic subsequence =",
           longLenStrictBitonicSub(arr, n))
 
# This code is contributed by sanjeev2552


C#




// C# implementation to find length of longest
// strict bitonic subsequence
using System;
using System.Collections.Generic;
 
class GfG
{
 
    // function to find length of longest
    // strict bitonic subsequence
    static int longLenStrictBitonicSub(int []arr, int n)
    {
        // hash table to map the array
        // element with the length of
        // the longest subsequence of
        // which it is a part of and
        // is the last/first element of
        // that subsequence
        Dictionary<int, int> inc = new Dictionary<int, int> ();
        Dictionary<int, int> dcr = new Dictionary<int, int> ();
 
        // arrays to store the length
        // of increasing and decreasing
        // subsequences which end at them
        // or start from them
        int []len_inc = new int[n];
        int []len_dcr = new int[n];
 
        // to store the length of longest strict
        // bitonic subsequence
        int longLen = 0;
 
        // traverse the array elements
        // from left to right
        for (int i = 0; i < n; i++)
        {
            // initialize current length
            // for element arr[i] as 0
            int len = 0;
 
            // if 'arr[i]-1' is in 'inc'
            if (inc.ContainsKey(arr[i] - 1))
                len = inc[arr[i] - 1];
 
            // update arr[i] subsequence length     
            // in 'inc' and in len_inc[]
            len_inc[i] = len + 1;
            if (inc.ContainsKey(arr[i]))
            {
                inc.Remove(arr[i]);
                inc.Add(arr[i], len_inc[i]);
            }
            else
                inc.Add(arr[i], len_inc[i]);
        }
 
        // traverse the array elements
        // from right to left
        for (int i = n - 1; i >= 0; i--)
        {
            // initialize current length
            // for element arr[i] as 0
            int len = 0;
 
            // if 'arr[i]-1' is in 'dcr'
            if (dcr.ContainsKey(arr[i] - 1))
                len = dcr[arr[i] - 1];
 
            // update arr[i] subsequence length in 'dcr'
            // and in len_dcr[]
            len_dcr[i] = len + 1;
            if (dcr.ContainsKey(arr[i]))
            {
                dcr.Remove(arr[i]);
                dcr.Add(arr[i], len_dcr[i]);
            }
            else
                dcr.Add(arr[i], len_dcr[i]);
        }
 
        // calculating the length of all the strict
        // bitonic subsequence
        for (int i = 0; i < n; i++)
            if (longLen < (len_inc[i] + len_dcr[i] - 1))
                longLen = len_inc[i] + len_dcr[i] - 1;
 
        // required longest length strict
        // bitonic subsequence
        return longLen;
    }
 
    // Driver code
    public static void Main(String[] args)
    {
        int []arr = {1, 5, 2, 3, 4, 5, 3, 2};
        int n = arr.Length;
        Console.WriteLine("Longest length strict " +
                            "bitonic subsequence = " +
                            longLenStrictBitonicSub(arr, n));
    }
}
 
// This code is contributed by Rajput-Ji


Javascript




<script>
 
// Javascript implementation to find length of longest
// strict bitonic subsequence
    
// function to find length of longest
// strict bitonic subsequence
function longLenStrictBitonicSub(arr, n)
{
    // hash table to map the array element with the
    // length of the longest subsequence of which
    // it is a part of and is the last/first element of
    // that subsequence
    var inc = new Map(), dcr = new Map();
     
    // arrays to store the length of increasing and
    // decreasing subsequences which end at them
    // or start from them 
    var len_inc = Array(n), len_dcr = Array(n);
     
    // to store the length of longest strict
    // bitonic subsequence
    var longLen = 0;
     
    // traverse the array elements
    // from left to right
    for (var i=0; i<n; i++)
    {
        // initialize current length
        // for element arr[i] as 0
        var len = 0;
           
        // if 'arr[i]-1' is in 'inc'
        if (inc.has(arr[i]-1))
            len = inc.get(arr[i]-1);
           
        // update arr[i] subsequence length in 'inc'   
        // and in len_inc[]
        len_inc[i] = len + 1;
        inc.set(arr[i], len_inc[i]);
         
    }
     
    // traverse the array elements
    // from right to left
    for (var i=n-1; i>=0; i--)
    {
        // initialize current length
        // for element arr[i] as 0
        var len = 0;
           
        // if 'arr[i]-1' is in 'dcr'
        if (dcr.has(arr[i]-1))
            len = dcr.get(arr[i]-1);
           
        // update arr[i] subsequence length in 'dcr'
        // and in len_dcr[]   
        len_dcr[i] = len + 1;
        dcr.set(arr[i], len_dcr[i]);
    }
     
    // calculating the length of all the strict
    // bitonic subsequence
    for (var i=0; i<n; i++)
        if (longLen < (len_inc[i] + len_dcr[i] - 1))
            longLen = len_inc[i] + len_dcr[i] - 1;
        
    // required longest length strict
    // bitonic subsequence
    return longLen;       
}
    
// Driver program to test above
var arr = [1, 5, 2, 3, 4, 5, 3, 2];
var n = arr.length;
document.write( "Longest length strict bitonic subsequence = "
      + longLenStrictBitonicSub(arr, n));
 
// This code is contributed by itsok.
</script>


Output

Longest length strict bitonic subsequence = 6

Time Complexity: O(n). 
Auxiliary Space: O(n).



Last Updated : 12 Feb, 2023
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads