Length of Longest Increasing Subsequences (LIS) using Segment Tree
Given an array arr[] of size N, the task is to count the number of longest increasing subsequences present in the given array.
Example:
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}.
Approach: An approach to the given problem has been already discussed using dynamic programming in this article.
This article suggests a different approach using segment trees. Follow the below steps to solve the given problem:
- Initialise the segment tree as an array of pairs initially containing pairs of (0, 0), where the 1st element represents the length of LIS and 2nd element represents the count of LIS of current length.
- The 1st element of the segment tree can be calculated similarly to the approach discussed in this article.
- The 2nd element of the segment tree can be calculated using the following steps:
- If cases where the length of left child > length of right child, the parent node becomes equal to the left child as LIS will that be of the left child.
- If cases where the length of left child < length of right child, the parent node becomes equal to the right child as LIS will that be of the right child.
- If cases where the length of left child = length of right child, the parent node becomes equal to the sum of the count of LIS of the left child and the right child.
- The required answer is the 2nd element of the root of the segment tree.
Below is the implementation of the above approach:
C++
// C++ implementation of the above approach #include <bits/stdc++.h> using namespace std; #define M 100000 // Stores the Segment tree vector<pair< int , int > > 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< int , int > 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< int , int > 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< int , int > a, pair< int , int > 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< int , int > > 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< int , int > 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< int , int > 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; } |
Java
import java.util.*; import java.io.*; // Java program for the above approach class GFG{ public static int M = 100000 ; // Stores the Segment tree public static ArrayList<ArrayList<Integer>> tree = new ArrayList<ArrayList<Integer>>(); // Function to update Segment tree, the root // of which contains the length of the LIS public static 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.get(idx).set( 0 , Math.max(tree.get(idx).get( 0 ), length_t)); tree.get(idx).set( 1 , 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.get( 2 * idx).get( 0 ) == tree.get( 2 * idx + 1 ).get( 0 )) { tree.set(idx, new ArrayList<Integer>( List.of(tree.get( 2 * idx).get( 0 ), tree.get( 2 * idx).get( 1 ) + tree.get( 2 * idx + 1 ).get( 1 )) )); } // If length_t of left > length_t right child else if (tree.get( 2 * idx).get( 0 ) > tree.get( 2 * idx + 1 ).get( 0 )) { tree.set(idx, new ArrayList<Integer>( List.of(tree.get( 2 * idx).get( 0 ), tree.get( 2 * idx).get( 1 )) )); } // If length_t of left < length_t right child else { tree.set(idx, new ArrayList<Integer>( List.of(tree.get( 2 * idx + 1 ).get( 0 ), tree.get( 2 * idx + 1 ).get( 1 )) )); } } // Function to find the LIS length // and count in the given range public static ArrayList<Integer> 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 new ArrayList<Integer>(tree.get(idx)); } // If intervals are not overlapping ArrayList<Integer> temp = new ArrayList<Integer>( List.of(Integer.MIN_VALUE, 0 ) ); if (end < query_start || query_end < start) { return new ArrayList<Integer>(temp); } // If intervals are partially overlapping int mid = (start + end) / 2 ; ArrayList<Integer> left_child = query(start, mid, query_start, query_end, 2 * idx); ArrayList<Integer> 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.get( 0 ) > right_child.get( 0 )) { return new ArrayList<Integer>(left_child); } // If length_t of right child is // greater than length_t of left child if (right_child.get( 0 ) > left_child.get( 0 )) { return new ArrayList<Integer>(right_child); } // If length_t of left // and right child are equal // return there sum return new ArrayList<Integer>( List.of( left_child.get( 0 ), left_child.get( 1 ) + right_child.get( 1 ) ) ); } // Function to find count // of LIS in the given array public static int countLIS( int arr[], int n) { // Generating value-index pair array ArrayList<ArrayList<Integer>> pair_array = new ArrayList<ArrayList<Integer>>(); for ( int i = 0 ; i < n ; i++){ pair_array.add( new ArrayList<Integer>( List.of(arr[i], i) )); } // Sort array of pairs with increasing order // of value and decreasing order of index Collections.sort(pair_array, new comp()); // Traverse the array // and perform query updates for ( int i = 0 ; i < n ; i++) { int update_idx = pair_array.get(i).get( 1 ); // 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] ArrayList<Integer> temp = query( 0 , n - 1 , 0 , update_idx - 1 , 1 ); // Update the segment tree update_tree( 0 , n - 1 , update_idx, temp.get( 0 ) + 1 , Math.max( 1 , temp.get( 1 )), 1 ); } // Stores the final answer ArrayList<Integer> ans = query( 0 , n - 1 , 0 , n - 1 , 1 ); // Return answer return ans.get( 1 ); } // Driver code public static void main(String args[]) { int arr[] = { 1 , 3 , 5 , 4 , 7 }; int n = arr.length; for ( int i = 0 ; i < 4 *M + 1 ; i++){ tree.add( new ArrayList<Integer>( List.of(Integer.MIN_VALUE, 0 ) )); } System.out.println(countLIS(arr, n)); } } // Comparator function to sort an array of pairs // in increasing order of their 1st element and // thereafter in decreasing order of the 2nd public class comp implements Comparator<ArrayList<Integer>>{ public int compare(ArrayList<Integer> a, ArrayList<Integer> b) { if (a.get( 0 ).equals(b.get( 0 ))) { return b.get( 1 ).compareTo(a.get( 1 )); } return a.get( 0 ).compareTo(b.get( 0 )); } } // This code is contributed by subhamgoyal2014. |
Javascript
<script> // Javascript implementation of the above approach let M = 100000 // Stores the Segment tree let tree = new Array(4 * M + 1).fill(0).map(() => []); // Function to update Segment tree, the root // of which contains the length of the LIS function update_tree(start, end, update_idx, length_t, count_c, idx) { // If the intervals // are overlapping completely if (start == end && start == update_idx) { tree[idx][0] = Math.max(tree[idx][0], length_t); tree[idx][1] = count_c; return ; } // If intervals are not overlapping if (update_idx < start || end < update_idx) { return ; } // If intervals are partially overlapping let mid = Math.floor((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][0] == tree[2 * idx + 1][0]) { tree[idx][0] = tree[2 * idx][0]; tree[idx][1] = tree[2 * idx][1] + tree[2 * idx + 1][1]; } // If length_t of left > length_t right child else if (tree[2 * idx][0] > tree[2 * idx + 1][0]) { 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 function query(start, end, query_start, query_end, idx) { // If the intervals // are overlapping completely if (query_start <= start && end <= query_end) { return tree[idx]; } // If intervals are not overlapping let temp = [Number.MIN_SAFE_INTEGER, 0]; if (end < query_start || query_end < start) { return temp; } // If intervals are partially overlapping let mid = Math.floor((start + end) / 2); let left_child = query(start, mid, query_start, query_end, 2 * idx); let 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[0] > right_child[0]) { return left_child; } // If length_t of right child is // greater than length_t of left child if (right_child[0] > left_child[0]) { return right_child; } // If length_t of left // and right child are equal // return there sum return [left_child[0], left_child[1] + right_child[1]]; } // Comparator function to sort an array of pairs // in increasing order of their 1st element and // thereafter in decreasing order of the 2nd function comp(a, b) { if (a[0] == b[0]) { return a[1] > b[1]; } return a[0] < b[0]; } // Function to find count // of LIS in the given array function countLIS(arr, n) { // Generating value-index pair array let pair_array = new Array(n).fill(0).map(() => []); for (let i = 0; i < n; i++) { pair_array[i][0] = arr[i]; pair_array[i][1] = i; } // Sort array of pairs with increasing order // of value and decreasing order of index pair_array.sort(comp); // Traverse the array // and perform query updates for (let i = 0; i < n; i++) { let update_idx = pair_array[i][1]; // 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] let temp = query(0, n - 1, 0, update_idx - 1, 1); // Update the segment tree update_tree(0, n - 1, update_idx, temp[0] + 1, Math.max(1, temp[1]), 1); } // Stores the final answer let ans = query(0, n - 1, 0, n - 1, 1); // Return answer return ans[1]; } // Driver Code let arr = [1, 3, 5, 4, 7]; let n = arr.length; document.write(countLIS(arr, n)); // This code is contributed by saurabh_jaiswal. </script> |
2
Time Complexity: O(N*log N)
Auxiliary Space: O(N)
Related Topic: Segment Tree
Please Login to comment...