Longest Bitonic Subsequence (original) (raw)
Last Updated : 07 Mar, 2025
Given an array **arr[] containing **n positive integers, a **subsequence of numbers is called bitonic if it is first strictly increasing, then strictly decreasing. The task is to find the length of the longest bitonic subsequence.
**Note: Only strictly increasing (no decreasing part) or a strictly decreasing sequence should not be considered as a bitonic sequence.
**Examples:
**Input: arr[]= [12, 11, 40, 5, 3, 1]
**Output: 5
**Explanation: The Longest Bitonic Subsequence is {12, 40, 5, 3, 1} which is of length 5.**Input: arr[] = [80, 60, 30]
**Output: 0
**Explanation: There is no possible Bitonic Subsequence.
Table of Content
- Using Recursion - O(n*(2^n)) Time and O(n) Space
- Using Top-Down DP (Memoization) - O(n^2) Time and O(n^2) Space
- Using Bottom-Up DP (Tabulation) - O(n^2) Time and O(n) Space
Using Recursion - O(n*(2^n)) Time and O(n) Space
The **recursive approach for finding the longest bitonic subsequence relies on breaking the problem into two parts for each potential peak:
- Calculate the Longest Increasing Subsequence (LIS) ending at the **current element.
- Calculate the Longest Decreasing Subsequence (LDS) starting from the current element.
At each step, the algorithm explores two choices:
- **Include the current element in the subsequence if it satisfies the increasing or decreasing condition.
- **Skip the current element and move to the next index.
**Recurrence Relation:
For any index i, the solution involves:
- Finding the LIS to the left: **if nums[i] < nums[prev]
**LIS(i, prev) = max(LIS(i-1, prev),1 + LIS(i-1, i))- Finding the LDS to the right: **if nums[i] < nums[prev]
**LDS(i, prev) = max(LDS(i+1, prev), 1 + LDS(i+1, i))**Base Cases:
- For LIS: **LIS(i, prev) = 0, if i < 0
- For LDS: **LDS(i, prev) = 0, if i >= n
C++ `
// C++ implementation to find longest Bitonic // subsequence using Recursion #include <bits/stdc++.h> using namespace std;
// Function to find the longest decreasing subsequence // to the left int left(int prev, int idx, vector& arr) { if (idx < 0) { return 0; }
// Check if nums[idx] can be included
// in decreasing subsequence
int include = 0;
if (arr[idx] < arr[prev]) {
include = 1 + left(idx, idx - 1, arr);
}
// Return the maximum of including
// or excluding nums[idx]
return max(include, left(prev, idx - 1, arr));
}
// Function to find the longest decreasing // subsequence to the right int right(int prev, int idx, vector& arr) { if (idx >= arr.size()) { return 0; }
// Check if nums[idx] can be included
// in decreasing subsequence
int include = 0;
if (arr[idx] < arr[prev]) {
include = 1 + right(idx, idx + 1, arr);
}
// Return the maximum of including or
// excluding nums[idx]
return max(include, right(prev, idx + 1, arr));
}
// Function to find the longest bitonic sequence int LongestBitonicSequence(vector& arr) { int maxLength = 0;
// Iterate over potential peaks in the array
for (int i = 1; i < arr.size() - 1; i++) {
// Find the longest decreasing subsequences
// on both sides of arr[i]
int leftLen = left(i, i - 1, arr);
int rightLen = right(i, i + 1, arr);
// Ensure both left and right subsequences are valid
if (leftLen == 0 || rightLen == 0) {
leftLen = 0;
rightLen = 0;
}
// Update maximum bitonic sequence length
maxLength = max(maxLength, leftLen + rightLen + 1);
}
// If no valid bitonic sequence, return 0
return (maxLength < 3) ? 0 : maxLength;
}
int main() {
vector<int> arr = {12, 11, 40, 5, 3, 1};
cout << LongestBitonicSequence(arr) << endl;
return 0;
}
Java
// Java implementation to find longest Bitonic // subsequence using Recursion import java.util.ArrayList; import java.util.*;
class GfG {
// Function to find the longest decreasing subsequence
// to the left
static int left(int prev, int idx, ArrayList<Integer> arr) {
if (idx < 0) {
return 0;
}
// Check if nums[idx] can be included
// in decreasing subsequence
int include = 0;
if (arr.get(idx) < arr.get(prev)) {
include = 1 + left(idx, idx - 1, arr);
}
// Return the maximum of including
// or excluding nums[idx]
return Math.max(include, left(prev, idx - 1, arr));
}
// Function to find the longest decreasing
// subsequence to the right
static int right(int prev, int idx, ArrayList<Integer> arr) {
if (idx >= arr.size()) {
return 0;
}
// Check if nums[idx] can be included
// in decreasing subsequence
int include = 0;
if (arr.get(idx) < arr.get(prev)) {
include = 1 + right(idx, idx + 1, arr);
}
// Return the maximum of including or
// excluding nums[idx]
return Math.max(include, right(prev, idx + 1, arr));
}
// Function to find the longest bitonic sequence
static int LongestBitonicSequence(ArrayList<Integer> arr) {
int maxLength = 0;
// Iterate over potential peaks in the array
for (int i = 1; i < arr.size() - 1; i++) {
// Find the longest decreasing subsequences
// on both sides of nums[i]
int leftLen = left(i, i - 1, arr);
int rightLen = right(i, i + 1, arr);
// Ensure both left and right subsequences are valid
if (leftLen == 0 || rightLen == 0) {
leftLen = 0;
rightLen = 0;
}
// Update maximum bitonic sequence length
maxLength = Math.max(maxLength, leftLen + rightLen + 1);
}
// If no valid bitonic sequence, return 0
return (maxLength < 3) ? 0 : maxLength;
}
public static void main(String[] args) {
ArrayList<Integer> arr
= new ArrayList<>(Arrays.asList(12, 11, 40, 5, 3, 1));
System.out.println(LongestBitonicSequence(arr));
}
}
Python
Python implementation to find longest Bitonic
subsequence using Recursion
Function to find the longest decreasing
subsequence to the left
def left(prev, idx, arr): if idx < 0: return 0
# Check if arr[idx] can be included in the
# decreasing subsequence
include = 0
if arr[idx] < arr[prev]:
include = 1 + left(idx, idx - 1, arr)
# Return the maximum of including or excluding arr[idx]
return max(include, left(prev, idx - 1, arr))
Function to find the longest decreasing subsequence
to the right
def right(prev, idx, arr): if idx >= len(arr): return 0
# Check if nums[idx] can be included in the
# decreasing subsequence
include = 0
if arr[idx] < arr[prev]:
include = 1 + right(idx, idx + 1, arr)
# Return the maximum of including or excluding arr[idx]
return max(include, right(prev, idx + 1, arr))
Function to find the longest bitonic sequence
def LongestBitonicSequence(arr): max_length = 0
# Iterate over potential peaks in the array
for i in range(1, len(arr) - 1):
# Find the longest decreasing subsequences
# on both sides of arr[i]
left_len = left(i, i - 1, arr)
right_len = right(i, i + 1, arr)
# Ensure both left and right subsequences are valid
if left_len == 0 or right_len == 0:
left_len = 0
right_len = 0
# Update maximum bitonic sequence length
max_length = max(max_length, left_len + right_len + 1)
# If no valid bitonic sequence, return 0
return 0 if max_length < 3 else max_length
if name == "main":
arr = [12, 11, 40, 5, 3, 1]
print(LongestBitonicSequence(arr))
C#
// C# implementation to find longest Bitonic // subsequence using Recursion using System; using System.Collections.Generic;
class GfG {
// Function to find the longest decreasing
// subsequence to the left
static int Left(int prev, int idx, List<int> arr) {
if (idx < 0) {
return 0;
}
// Check if nums[idx] can be included in
// decreasing subsequence
int include = 0;
if (arr[idx] < arr[prev]) {
include = 1 + Left(idx, idx - 1, arr);
}
// Return the maximum of including or excluding nums[idx]
return Math.Max(include, Left(prev, idx - 1, arr));
}
// Function to find the longest decreasing
// subsequence to the right
static int Right(int prev, int idx, List<int> arr) {
if (idx >= arr.Count) {
return 0;
}
// Check if nums[idx] can be included
// in decreasing subsequence
int include = 0;
if (arr[idx] < arr[prev]) {
include = 1 + Right(idx, idx + 1, arr);
}
// Return the maximum of including or excluding nums[idx]
return Math.Max(include, Right(prev, idx + 1, arr));
}
// Function to find the longest bitonic sequence
static int LongestBitonicSequence(List<int> arr) {
int maxLength = 0;
// Iterate over potential peaks in the array
for (int i = 1; i < arr.Count - 1; i++) {
// Find the longest decreasing subsequences
// on both sides of nums[i]
int leftLen = Left(i, i - 1, arr);
int rightLen = Right(i, i + 1, arr);
// Ensure both left and right subsequences are valid
if (leftLen == 0 || rightLen == 0) {
leftLen = 0;
rightLen = 0;
}
// Update maximum bitonic sequence length
maxLength = Math.Max(maxLength,
leftLen + rightLen + 1);
}
// If no valid bitonic sequence, return 0
return (maxLength < 3) ? 0 : maxLength;
}
static void Main() {
List<int> arr
= new List<int> { 12, 11, 40, 5, 3, 1 };
Console.WriteLine(LongestBitonicSequence(arr));
}
}
JavaScript
// Javascript implementation to find longest Bitonic // subsequence using Recursion