首先,先明白子串和子序列之间的差别:
以字符串 abcdefgh 为例:
1. 字符子串指的是字符串中连续的字符
eg. abc, efg····
2. 字符子序列指的是字符串中先后顺序一致但不一定连续的字符
eg. adg, cdgh····
可以去掉字符串中的部分字符,但不可改变其前后顺序。
最长上升子序列(LIS)
序列(1, 7, 3, 5, 9, 4, 8) ,其最长上升子序列长度为4,其中一条LIS(1,3,5,8)
ps.与最长非降序子序列(二者区别就是序列中是否可以有相等的数)同理。
要用集合的观念来理解此类问题:
子序列、公共子序列以及最长公共子序列都不唯一
对于固定的数组,虽然LIS序列不一定唯一,但LIS的长度是唯一的
解决方案:
采用贪心+二分 O(nlogn)
由贪心的思想:对于一个上升子序列,显然其结尾元素越小,越有利于在后面接其他的元素,也就越可能变得更长。
只需要维护一个low数组,具体情况:
1. 如果读入的数x > low[end],就将x读入到low的末尾
2. x <= low[end], 就用x来更新low,由于采用这样的做法low中插入的数据都是有序的,一定都是单调递增(单调不减也可以),就可以采用二分查找的方法lower_bound( )来找到第一个大于等于x的数,并用x来取代low中的数,本质是贪心算法的体现。
3. 可以发现只用步骤(1)可以增加LIS的长度,而步骤(2)的目的在于贪心为接下来的操作做铺垫
4. 注意!low中单序列并不一定是正确的最长上升子序列,该做法只能得到LIS的长度,并不一定能得到正确的LIS序列,因为二分插入数字的,有可能将排序较后的数插在排序比它前的数的前面,这样的序列就不满足有序了
但是这样做的依据是二分查找插入并没有改变LIS的长度,这一步的意义更在于贪心的思想,即代表一种可能性,为之后的更新做了铺垫。
总之low并不一定表示最长上升子序列,它只表示相应最长子序列长度的排好序的最小序列,它可以反映LIS的长度。
code:
//核心代码1 const int MAXN; int a[MAXN] int low[MAXN]; int main(){ int n; cin >> n; memset(low,0x3f,sizeof low); for(int i=0;i<n;i++) cin >> a[i]; low[1] = a[1]; int num = 1; for(int i=1;i<n;i++){ if(a[i] > low[num]) low[++num] = a[i]; else 二分查找 low[ ] = a[i]; } cout << num; return 0; }
//代码2 STL实现 #include<iostream> #include<vector> using namespace std; const int MAXN = 1e5+10; int a[MAXN]; vector<int> vec; int main(){ int n; cin >> n; for(int i=1;i<=n;i++) cin >> a[i]; for(int i=1;i<=n;i++){ if(vec.empty() || a[i]>vec.back()) vec.push_back(a[i]); else{ int pos = lower_bound(vec.begin(),vec.end(),a[i])-vec.begin(); vec[pos] = a[i]; } } cout << vec.size(); return 0; }
扩展运用:
狄尔沃斯定理(Dilworth's theorem)
百度百科:亦称偏序集分解定理,是关于偏序集的极大极小的定理,该定理断言:对于任意有限偏序集,其最大反链中元素的数目必等于最小链划分中链的数目。此定理的对偶形式亦真,它断言:对于任意有限偏序集,其最长链中元素的数目必等于其最小反链划分中反链的数目,由偏序集P按如下方式产生的图G称为偏序集的可比图:G的节点集由P的元素组成,而e为G中的边,仅当e的两端点在P中是可比较的,有限全序集的可比图为完全图
point 1:对于任意有限偏序集,其最大反链中元素的数目必等于最小链划分中链的数目。
point 2:对偶形式亦真,断言:对于任意有限偏序集,其最长链中元素的数目必等于其最小反链划分中反链的数目
point 3:最小链覆盖(使链最少)= 最长反链长度 = 偏序集宽度
最小反链覆盖 = 最长链长度 = 偏序集深度
栗子:
1 2 3 2 3
要把 1 2 3 2 3 从序列变为集合(p,v)的形式{(1,2),(2,2),(3,3),(4,2),(5,3)},第一个是序数第二个是对应的数,并在此基础上定义关系 <=:pi<=pj&&vi<=vj。
最*小*上升子序列划分个数 {1,2,2,3}与{3} —— 两个
等于最*长”反链长度 (3,2) ——同样是两个
反之则是
最小反链划分{1} ,{2} ,{3,2},{3} ——4个
等于最长不降子序列长度 {1,2,2,3} ——同样4个
假如是最长上升子序列 就定义关系为 <:pi<pj&&vi<vj即可
例题:


样例结果:
4条轨道的列车:
8 4 2 1
5 3
6 9
7
其LIS为
2 3 6 7
长度为4
终上所述,采用上面分析的代码就可以AC此题
浙公网安备 33010602011771号