Problem statement

A Bitonic Sequence is a sequence of numbers that is first strictly increasing and then strictly decreasing.
A strictly ascending order sequence is also considered bitonic, with the decreasing part as empty, and same for a strictly descending order sequence.

For example, the sequences [1, 3, 5, 3, 2], [1, 2, 3, 4] are bitonic, whereas the sequences [5, 4, 1, 4, 5] and [1, 2, 2, 3] are not.

You are given an array ‘arr’ consisting of ‘n’ positive integers.

Find the length of the longest bitonic subsequence of ‘arr’.
Example :

Input: 'arr' = [1, 2, 1, 2, 1]

Output: 3

Explanation: The longest bitonic subsequence for this array will be [1, 2, 1]. Please note that [1, 2, 2, 1] is not a valid bitonic subsequence, because the consecutive 2's are neither strictly increasing, nor strictly decreasing.

Detailed explanation ( Input/output format, Notes, Images )

Sample Input 1 :
5 
1 2 1 2 1
Sample Output 1:
3

Explanation For Sample Input 1:

The longest bitonic subsequence for this array will be [1, 2, 1]. Please note that [1, 2, 2, 1] is not a valid bitonic subsequence, because the consecutive 2's are neither strictly increasing, nor strictly decreasing.
Sample input 2 :
5
1 2 1 3 4
Sample Output 2 :
4

Explanation For Sample Input 2:

The longest bitonic sequence for this array will be [1, 2, 3, 4].
Expected time complexity :
The expected time complexity is O(n ^ 2).
Constraints:
1 <= 'n' <= 10^3
1 <= 'arr[i]' <= 10^5

Approach - Bottom Up

  • Find LIS and then LDS and then combine
  • O(n^2), O(n)
class Solution {
    public int longestBitonicSubsequence(int[] nums) {
        int n = nums.length;
        int[] lis = new int[n]; // Longest Increasing Subsequence up to i
        int[] lds = new int[n]; // Longest Decreasing Subsequence from i
 
        // Step 1: Fill LIS
        Arrays.fill(lis, 1);
        for (int i = 1; i < n; i++) {
            for (int j = 0; j < i; j++) {
                if (nums[j] < nums[i])
                    lis[i] = Math.max(lis[i], lis[j] + 1);
            }
        }
 
        // Step 2: Fill LDS
        Arrays.fill(lds, 1);
        for (int i = n - 2; i >= 0; i--) {
            for (int j = n - 1; j > i; j--) {
                if (nums[j] < nums[i])
                    lds[i] = Math.max(lds[i], lds[j] + 1);
            }
        }
 
        // Step 3: Combine LIS and LDS
        int maxLen = 1;
        for (int i = 0; i < n; i++) {
            maxLen = Math.max(maxLen, lis[i] + lds[i] - 1);
        }
 
        return maxLen;
    }
}