A bitonic subsequence is one that first increases and then decreases. To find the longest bitonic subsequence, we can combine the longest increasing subsequence (LIS) ending at each index with the longest decreasing subsequence (LDS) starting from that index. The peak of the bitonic sequence is where these two meet, and the answer is the maximum sum of LIS and LDS at any index, minus one to avoid double-counting the peak.
For e.g., the longest bitonic subsequence (LBS) in the array nums = [0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15], can be shown as shown below:
LIS(0) = 1 [0]// a single element forms an increasing subsequenceLIS(1) = 2 [0, 8]LIS(2) = 2 [0, 4]LIS(3) = 3 [0, 8, 12] or [0, 4, 12]LIS(4) = 2 [0, 2]LIS(5) = 3 [0, 8, 10] or [0, 4, 10] or [0, 2, 10]LIS(6) = 3 [0, 4, 6] or [0, 2, 6]LIS(7) = 4 [0, 8, 12, 14] or [0, 4, 12, 14] or [0, 8, 10, 14] or [0, 4, 10, 14] or [0, 4, 6, 14] or [0, 2, 6, 14]...
For example, LIS(7) is formed by adding nums[7] to the LIS of indices 3, 5, and 6. In general, LIS(i) is built by extending nums[i] to the longest LIS(j) for all j < i where nums[j] < nums[i]. This leads to the recurrence:
1
LIS(i) = max{1 + LIS(j)} for all j < i and nums[j]< nums[i]
classSolution {
public:int longestBitonicSubsequence(vector<int>& nums) {
int n = nums.size();
vector<int> lis(n, 1), lds(n, 1);
for (int i =1; i < n; ++i)
for (int j =0; j < i; ++j)
if (nums[i] > nums[j] && lis[i] < lis[j] +1)
lis[i] = lis[j] +1;
for (int i = n -2; i >=0; --i)
for (int j = n -1; j > i; --j)
if (nums[i] > nums[j] && lds[i] < lds[j] +1)
lds[i] = lds[j] +1;
int ans =0;
for (int i =0; i < n; ++i)
ans = max(ans, lis[i] + lds[i] -1);
return ans;
}
};
classSolution {
publicintlongestBitonicSubsequence(int[] nums) {
int n = nums.length;
int[] lis =newint[n], lds =newint[n];
Arrays.fill(lis, 1);
Arrays.fill(lds, 1);
for (int i = 1; i < n; i++)
for (int j = 0; j < i; j++)
if (nums[i]> nums[j]&& lis[i]< lis[j]+ 1)
lis[i]= lis[j]+ 1;
for (int i = n - 2; i >= 0; i--)
for (int j = n - 1; j > i; j--)
if (nums[i]> nums[j]&& lds[i]< lds[j]+ 1)
lds[i]= lds[j]+ 1;
int ans = 0;
for (int i = 0; i < n; i++)
ans = Math.max(ans, lis[i]+ lds[i]- 1);
return ans;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
classSolution {
funlongestBitonicSubsequence(nums: IntArray): Int {
val n = nums.size
val lis = IntArray(n) { 1 }
val lds = IntArray(n) { 1 }
for (i in1 until n)
for (j in0 until i)
if (nums[i] > nums[j] && lis[i] < lis[j] + 1)
lis[i] = lis[j] + 1for (i in n - 2 downTo 0)
for (j in n - 1 downTo i + 1)
if (nums[i] > nums[j] && lds[i] < lds[j] + 1)
lds[i] = lds[j] + 1var ans = 0for (i in0 until n)
ans = maxOf(ans, lis[i] + lds[i] - 1)
return ans
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
deflongest_bitonic_subsequence(nums: list[int]) -> int:
n = len(nums)
lis = [1] * n
lds = [1] * n
for i in range(1, n):
for j in range(i):
if nums[i] > nums[j] and lis[i] < lis[j] +1:
lis[i] = lis[j] +1for i in range(n -2, -1, -1):
for j in range(n -1, i, -1):
if nums[i] > nums[j] and lds[i] < lds[j] +1:
lds[i] = lds[j] +1 ans =0for i in range(n):
ans = max(ans, lis[i] + lds[i] -1)
return ans