Longest Increasing Subsequence
来源:互联网 发布:亚马逊windows 编辑:程序博客网 时间:2024/06/03 20:52
Longest Increasing Subsequence
Longest Increasing Subsequence问题是找到给定序列的子序列,其中子序列的元素按照排序顺序排列,从最低到最高,并且子序列尽可能长。这个子序列不一定是连续的,也不是唯一的。
例如,考虑子序列{0,8,4,12,2,10,6,14,1,9,5,11,13,3,11,7,15}
最长增长的子序列是{0,2,6,9,11,15}
这个序列长度为6;输入序列没有7个成员增加的子序列。这个例子中Longest Increasing Subsequence不是唯一的:例如,
{0,4,6,9,11,15}或 {0,4,6,9,13,15}
是相同输入序列中长度相等的其他增加的子序列。
我们已经讨论了使用动态规划的LIS的O(n2)时间复杂度解决方案。在这篇文章中,讨论了一个O(nlogn)时间非DP解决方案。
令S [i]定义为结束长度为i的递增序列的最小整数。现在遍历输入集合的每个整数X,并执行以下操作:
如果X超过S中的最后一个元素,则将X附加到S的末尾。这实际上意味着我们已经找到了一个新的最大的LIS。
否则在S中找到最小的元素,它大于等于X,并将其替换为X.由于S随时进行排序,所以可以使用log(N)时间内的二进制搜索找到该元素。
我们借助一个例子来说明这一点。考虑下面的整数数组
{2,6,3,4,1,2,9,5,8}
以下是算法遵循的步骤 -
初始化为空集S = {}插入2 - S = {2} - 最大LIS插入6 - S = {2,6} - 新的最大LIS插入3 - S = {2,3} - 用3替换6插入4-S = {2,3,4} - 新的最大LIS插入1 - S = {1,3,4} - 用1替换2插入2 - S = {1,2,4} - 用2替换3插入9 - S = {1,2,4,9} - 新的最大LIS插入5 - S = {1,2,4,5} - 用5替换9插入8 - S = {1,2,4,5,8} - 最大的LIS
那么LIS的长度是5(S的大小)。请注意,这里S [i]被定义为结束长度为i的递增序列的最小整数。因此,S不代表实际的序列,而S的大小代表LIS的长度。
以下解决方案使用std :: set实现为红黑二进制搜索树,其具有用于插入的最坏情况时间复杂度为O(logn)。
C ++实现 -
#include <bits/stdc++.h>using namespace std;//给定数组中查找长度最长的增加子序列的函数int findLISLength(int arr[], int n){ //创建一个空的有序集S.在S中的第i个元素被定义为//结束长度为i的递增序列的最小整数 set<int> S; //逐个处理每个元素 for (int i = 0; i < n; i++) { //将当前元素插入到集合中 auto ret = S.insert(arr[i]); //获取迭代器插入元素 set<int>::iterator it; if (ret.second) it = ret.first; //如果元素没有插入到最后,然后删除下一个 //更大的元素从集合 if (++it != S.end()) S.erase(it); } // LIS的长度是集合中的元素数 return S.size();}// 主功能int main(){ int arr[] = { 2, 6, 3, 4, 1, 2, 9, 5, 8 }; int n = sizeof(arr) / sizeof(arr[0]); cout << "Length of LIS is " << findLISLength(arr, n) << endl; return 0;}
Output:
Length of LIS is 5
如何打印LIS?
为了使事情变得更简单,我们可以将S中的索引保留在S中,而不是实际的整数。那就是我们不保留{1,2,4,5,8},而是保留{4,5,3,7,8},因为arr [4] = 1,arr [5] = 2,arr [3] = 4,arr [7] = 5,arr [8] = 8。
要重建实际的LIS,我们必须使用一个父数组。让父母[i]成为LIS中索引i的元素的前身,以索引i的元素结尾。如果我们正确地更新了父数组,实际的LIS是:
ARR [S [lastElementOfS]]ARR [父[S [lastElementOfS]]],ARR [父[父[S [lastElementOfS]]]],
下面的解决方案将实际整数和它们的索引存储在集合中以便于实现 -
#include <bits/stdc++.h>using namespace std;//数据结构存储元素及其索引在数组中struct Node{ int elem; int index;};//重载比较运算符插入到集合中inline bool operator<(const Node& lhs, const Node& rhs){ return lhs.elem < rhs.elem;}//使用父数组打印LIS的功能void print(int input[], auto parent, set<Node> S){ //容器以相反的顺序存储LIS stack<int> lis; //从S的最后一个元素开始 int index = S.rbegin()->index; //获取LIS的长度 int n = S.size(); // retrieve LIS from parent array while (n--) { lis.push(input[index]); index = parent[index]; } //打印LIS cout << "LIS is "; while(!lis.empty()) { cout << lis.top() << " "; lis.pop(); }}//给定数组中查找最长递增子序列的函数void printLIS(int arr[], int n){ //创建一个空的有序集合S(S中的第i个元素被定义为 //结束长度增加序列的最小整数i) set<Node> S; // parent [i]将存储索引i的元素的前身 // LIS以索引i的元素结尾 map<int, int> parent; //逐个处理每个元素 for (int i = 0; i < n; i++) { //从当前元素及其索引构造节点 Node curr = {arr[i], i}; //将当前节点插入到集合中并获取迭代器 //插入节点 auto it = S.insert(curr).first; //如果最后没有插入节点,则删除下一个节点 if (++it != S.end()) S.erase(it); //获取迭代器到当前节点并更新父节点 it = S.find(curr); parent[i] = (--it)->index; } //使用父地图打印LIS print(arr, parent, S);}// 主功能int main(){ int arr[] = { 2, 6, 3, 4, 1, 2, 9, 5, 8 }; int n = sizeof(arr) / sizeof(arr[0]); printLIS(arr, n); return 0;}
Output:
LIS is 2 3 4 5 8
上述解的时间复杂度为O(nlog(n)),程序使用的辅助空间为O(n)。
阅读全文
0 0
- Longest Increasing Subsequence
- 【DP】 Longest Increasing Subsequence
- Longest Increasing Subsequence(LIS)
- Longest Increasing Subsequence
- 【算法】Longest Increasing Subsequence
- Longest Increasing Subsequence
- Longest Increasing Subsequence
- Longest Increasing Subsequence
- Longest Increasing Subsequence
- Longest Increasing Subsequence(LIS)
- Longest Increasing Subsequence
- [DP]Longest Increasing Subsequence
- The Longest increasing subsequence
- [刷题]Longest Increasing Subsequence
- longest-increasing-subsequence
- Longest Increasing Subsequence
- codeforces568E.Longest Increasing Subsequence
- Longest Increasing Subsequence
- CSS div水平垂直居中和div置于底部
- sql语句case when的使用
- mvc与三层结构终极区别
- HDU 3714
- STM32上使用UCOSII--任务
- Longest Increasing Subsequence
- 一个DIV调用多个CSS样式
- 关于ASP.NET页面打印技术的总结
- 低等数论1
- GridView和CheckBox结合实现可选择删除
- NodeMCU 使用Arduino SPI点亮OLED12864
- 爱迪生转
- JUC锁-06之 Condition条件
- String转int