LIS с использованием дерева сегментов
Вам дан массив целых чисел, вам нужно найти длину самой длинной возрастающей подпоследовательности.
Для решения проблемы может быть 4 подхода.
1) Грубая сила:
В этом подходе мы пытаемся найти все возрастающие подпоследовательности, а затем возвращаем максимальную длину самой длинной возрастающей подпоследовательности. Для этого мы используем рекурсивную функцию, которая возвращает длину LIS, возможную от текущего элемента и далее.
Сложность времени: 
Космическая сложность: 
2) динамическое программирование
Этот подход основан на том факте, что LIS до i-го индекса не зависит от последующих (n-i + 1) элементов. Кроме того, LIS до (i + 1) -го элемента может быть вычислен путем проверки LIS, полученного от индекса 0 до i.
Подход динамического программирования
Сложность времени: 
Космическая сложность: 
3) Использование двоичного поиска
Элементы хранятся в возрастающем порядке в массиве DP, где индекс определяется с помощью двоичного поиска. Длина массива дает длину LIS.
Сложность времени: 
Космическая сложность: 
Пожалуйста, обратитесь к разделу Построение самой длинной возрастающей подпоследовательности (N log N) для получения подробной информации.
4) Использование дерева сегментов
Элементы сначала сортируются в порядке возрастания с сохранением их исходных индексов. Для строго увеличивающейся LIS для равных элементов элемент с более высоким индексом получает более раннюю позицию, чем более низкий. Это может быть сохранено в массиве пар.
Теперь они заполнены в дереве сегментов. В соответствии с их положением в отсортированном массиве они заполняются в дереве сегментов в листьях, соответствующих их исходным индексам.
Первоначально дерево сегментов было инициализировано нулями. Теперь предположим, что мы обработали i-й элемент в отсортированном массиве. На (i + 1) -й итерации пусть исходная позиция значения равна j.
Затем он заполнит j-й лист в дереве сегментов, значение которого будет максимальным значением листьев от 0 до (j-1) +1.
(Длина LIS, образованного элементами, меньшими, чем в предшествующем подмассиве, и +1 для его включения)
Arr [] = {5, 1, 3, 9} Индексы: {0, 1, 2, 3}
Sorted_Arr [] = {1, 3, 5, 9} Original_Indices: {1, 2, 0, 3} Индексы: {0, 1, 2, 3}


C++
// Finding the Longest Increasing Subsequence using// Segment Tree#include <bits/stdc++.h>using namespace std;// function to compare two pairsint compare(pair<int, int> p1, pair<int, int> p2){ /* For same values, element with the higher index appear earlier in the sorted array. This is for strictly increasing subsequence. For increasing subsequence, the lower index appears earlier in the sorted array. */ if (p1.first == p2.first) return p1.second > p2.second; // Sorting the array according to their values. return p1.first < p2.first;}// Building the entire Segment tree, the root of which// contains the length of the LISvoid buildTree(int* tree, int pos, int low, int high, int index, int value){ // index is the original index of current element // If the index is not present in the given range, // then simply return if (index < low || index > high) return; // If low == high then the current position should // be updated to the value if (low == high) { tree[pos] = value; return; } int mid = (high + low) / 2; // Recursively call the function on the // child nodes buildTree(tree, 2 * pos + 1, low, mid, index, value); buildTree(tree, 2 * pos + 2, mid + 1, high, index, value); // Assign the current position the max of the 2 child // nodes tree[pos] = max(tree[2 * pos + 1], tree[2 * pos + 2]);}// Function to query the Segment tree and return the// value for a given rangeint findMax(int* tree, int pos, int low, int high, int start, int end){ // Query: Same as the query function of Segment tree // If the current range is totally inside the query // range, return the value of current position if (low >= start && high <= end) return tree[pos]; // If it is out of bound, return the minimum which // would be 0 in this case if (start > high || end < low) return 0; // Partial overlap int mid = (high + low) / 2; // Call findMax on child nodes recursively and // return the maximum of the two return max(findMax(tree, 2 * pos + 1, low, mid, start, end), findMax(tree, 2 * pos + 2, mid + 1, high, start, end));}int findLIS(int arr[], int n){ // The array of pairs stores the integers and // indices in p[i] pair<int, int> p[n]; for (int i = 0; i < n; i++) { p[i].first = arr[i]; p[i].second = i; } // Sorting the array in increasing order // of the elements sort(p, p + n, compare); // Calculating the length of the segment-tree int len = pow(2, (int)(ceil(sqrt(n))) + 1) - 1; int tree[len]; // Initializing the tree with zeroes memset(tree, 0, sizeof(tree)); // Building the segment-tree, the root node of // which contains the length of LIS for the n // elements for (int i = 0; i < n; i++) { buildTree(tree, 0, 0, n - 1, p[i].second, findMax(tree, 0, 0, n - 1, 0, p[i].second) + 1); } return tree[0];}// Driver codeint main(){ int arr[] = { 10, 22, 9, 33, 21, 50, 41, 60 }; int n = sizeof(arr) / sizeof(arr[0]); cout << "Length of the LIS: " << findLIS(arr, n); return 0;} |
Java
// Finding the Longest Increasing Subsequence// using Segment Treeimport java.io.*;import java.util.*;class Pair{ int first; int second;}class GFG{// Building the entire Segment tree, the root of which// contains the length of the LISstatic void buildTree(int[] tree, int pos, int low, int high, int index, int value){ // Index is the original index of current element // If the index is not present in the given range, // then simply return if (index < low || index > high) return; // If low == high then the current position // should be updated to the value if (low == high) { tree[pos] = value; return; } int mid = (high + low) / 2; // Recursively call the function on the // child nodes buildTree(tree, 2 * pos + 1, low, mid, index, value); buildTree(tree, 2 * pos + 2, mid + 1, high, index, value); // Assign the current position the max of // the 2 child nodes tree[pos] = Math.max(tree[2 * pos + 1], tree[2 * pos + 2]);}// Function to query the Segment tree and// return the value for a given rangestatic int findMax(int[] tree, int pos, int low, int high, int start, int end){ // Query: Same as the query function of Segment // tree. If the current range is totally inside // the query range, return the value of current // position if (low >= start && high <= end) return tree[pos]; // If it is out of bound, return the minimum // which would be 0 in this case if (start > high || end < low) return 0; // Partial overlap int mid = (high + low) / 2; // Call findMax on child nodes recursively // and return the maximum of the two return Math.max(findMax(tree, 2 * pos + 1, low, mid, start, end), findMax(tree, 2 * pos + 2, mid + 1, high, start, end));}static int findLIS(int arr[], int n){ // The array of pairs stores the integers // and indices in p[i] List<Pair> p = new ArrayList<Pair>(); for(int i = 0; i < n; i++) { Pair p1 = new Pair(); p1.first = arr[i]; p1.second = i; p.add(p1); } // Sorting the array in increasing order // of the elements Collections.sort(p, (p1, p2) -> { /* For same values, element with the higher index appear earlier in the sorted array. This is for strictly increasing subsequence. For increasing subsequence, the lower index appears earlier in the sorted array. */ if (p1.first == p2.first) return p2.second - p1.second; // Sorting the array according to their values. return p1.first - p2.first; }); // Calculating the length of the segment-tree int len = (int)(Math.pow( 2, (int)(Math.ceil(Math.sqrt(n))) + 1)) - 1; int[] tree = new int[len]; // Building the segment-tree, the root node of // which contains the length of LIS for the n // elements for(int i = 0; i < n; i++) { buildTree(tree, 0, 0, n - 1, p.get(i).second, findMax(tree, 0, 0, n - 1, 0, p.get(i).second) + 1); } return tree[0];}// Driver Codepublic static void main(String[] args){ int arr[] = { 10, 22, 9, 33, 21, 50, 41, 60 }; int n = arr.length; System.out.println("Length of the LIS: " + findLIS(arr, n));}}// This code is contributed by jithin |
Length of the LIS: 5
Сложность времени: 
Космическая сложность: 
Эта статья предоставлена Притамом Патхаком. Если вам нравится GeeksforGeeks, и вы хотели бы внести свой вклад, вы также можете написать статью с помощью provide.geeksforgeeks.org или отправить ее по электронной почте на deposit@geeksforgeeks.org. Посмотрите, как ваша статья появляется на главной странице GeeksforGeeks, и помогите другим гикам.
Пожалуйста, напишите комментарии, если вы обнаружите что-то неправильное, или вы хотите поделиться дополнительной информацией по теме, обсужденной выше.