使用段树的最长递增子序列 (LIS) 的长度
给定一个大小为N的数组arr[] ,任务是计算给定数组中存在的最长递增子序列的数量。
例子:
Input: arr[] = {2, 2, 2, 2, 2}
Output: 5
Explanation: The length of the longest increasing subsequence is 1, i.e. {2}. Therefore, count of longest increasing subsequences of length 1 is 5.
Input: arr[] = {1, 3, 5, 4, 7}
Output: 2
Explanation: The length of the longest increasing subsequence is 4, and there are 2 longest increasing subsequences of length 4, i.e. {1, 3, 4, 7} and {1, 3, 5, 7}.
方法:本文已经讨论了使用动态规划解决给定问题的方法。
本文提出了一种使用线段树的不同方法。请按照以下步骤解决给定的问题:
- 将段树初始化为一个对数组,最初包含 (0, 0) 对,其中第一个元素表示 LIS 的长度,第二个元素表示 LIS 的长度 element 表示当前长度的 LIS 的计数。
- 可以类似于本文中讨论的方法来计算段树的第一个元素。
- 可以使用以下步骤计算线段树的第二个元素:
- 如果左孩子的长度>右孩子的长度,则父节点变得等于左孩子,因为 LIS 将成为左孩子。
- 如果左孩子的长度<右孩子的长度,则父节点变得等于右孩子,因为 LIS 将成为右孩子。
- 如果左孩子的长度=右孩子的长度,则父节点等于左孩子和右孩子的LIS计数之和。
- 所需答案是线段树根的第二个元素。
下面是上述方法的实现:
C++
// C++ implementation of the above approach
#include
using namespace std;
#define M 100000
// Stores the Segment tree
vector > tree(4 * M + 1);
// Function to update Segment tree, the root
// of which contains the length of the LIS
void update_tree(int start, int end,
int update_idx, int length_t,
int count_c, int idx)
{
// If the intervals
// are overlapping completely
if (start == end
&& start == update_idx) {
tree[idx].first
= max(tree[idx].first, length_t);
tree[idx].second = count_c;
return;
}
// If intervals are not overlapping
if (update_idx < start
|| end < update_idx) {
return;
}
// If intervals are partially overlapping
int mid = (start + end) / 2;
update_tree(start, mid, update_idx,
length_t, count_c,
2 * idx);
update_tree(mid + 1, end, update_idx,
length_t, count_c,
2 * idx + 1);
// If length_t of left and
// right child are equal
if (tree[2 * idx].first
== tree[2 * idx + 1].first) {
tree[idx].first
= tree[2 * idx].first;
tree[idx].second
= tree[2 * idx].second
+ tree[2 * idx + 1].second;
}
// If length_t of left > length_t right child
else if (tree[2 * idx].first
> tree[2 * idx + 1].first) {
tree[idx] = tree[2 * idx];
}
// If length_t of left < length_t right child
else {
tree[idx] = tree[2 * idx + 1];
}
}
// Function to find the LIS length
// and count in the given range
pair query(int start, int end,
int query_start,
int query_end, int idx)
{
// If the intervals
// are overlapping completely
if (query_start <= start
&& end <= query_end) {
return tree[idx];
}
// If intervals are not overlapping
pair temp({ INT32_MIN, 0 });
if (end < query_start
|| query_end < start) {
return temp;
}
// If intervals are partially overlapping
int mid = (start + end) / 2;
auto left_child
= query(start, mid, query_start,
query_end, 2 * idx);
auto right_child
= query(mid + 1, end, query_start,
query_end, 2 * idx + 1);
// If length_t of left child is greater
// than length_t of right child
if (left_child.first > right_child.first) {
return left_child;
}
// If length_t of right child is
// greater than length_t of left child
if (right_child.first > left_child.first) {
return right_child;
}
// If length_t of left
// and right child are equal
// return there sum
return make_pair(left_child.first,
left_child.second
+ right_child.second);
}
// Comparator function to sort an array of pairs
// in increasing order of their 1st element and
// thereafter in decreasing order of the 2nd
bool comp(pair a, pair b)
{
if (a.first == b.first) {
return a.second > b.second;
}
return a.first < b.first;
}
// Function to find count
// of LIS in the given array
int countLIS(int arr[], int n)
{
// Generating value-index pair array
vector > pair_array(n);
for (int i = 0; i < n; i++) {
pair_array[i].first = arr[i];
pair_array[i].second = i;
}
// Sort array of pairs with increasing order
// of value and decreasing order of index
sort(pair_array.begin(),
pair_array.end(), comp);
// Traverse the array
// and perform query updates
for (int i = 0; i < n; i++) {
int update_idx = pair_array[i].second;
// If update index is the 1st index
if (update_idx == 0) {
update_tree(0, n - 1, 0, 1, 1, 1);
continue;
}
// Query over the interval [0, update_idx -1]
pair temp
= query(0, n - 1, 0,
update_idx - 1, 1);
// Update the segment tree
update_tree(0, n - 1, update_idx,
temp.first + 1,
max(1, temp.second), 1);
}
// Stores the final answer
pair ans
= query(0, n - 1, 0, n - 1, 1);
// Return answer
return ans.second;
}
// Driver Code
int main()
{
int arr[] = { 1, 3, 5, 4, 7 };
int n = sizeof(arr) / sizeof(int);
cout << countLIS(arr, n);
return 0;
}
Javascript
输出
2
时间复杂度: O(N*log N)
辅助空间: O(N)