最长不下降子序列nlogn算法详解
来源:互联网 发布:淘宝图片轮播怎么做 编辑:程序博客网 时间:2024/06/04 20:13
很赞的讲解,建议移步至原博文地址去支持博主:http://www.cnblogs.com/itlqs/p/5743114.html
原博文:
今天花了很长时间终于弄懂了这个算法……毕竟找一个好的讲解真的太难了,所以励志我要自己写一个好的讲解QAQ
这篇文章是在懂了这个问题n^2解决方案的基础上学习。
解决的问题:给定一个序列,求最长不下降子序列的长度(nlogn的算法没法求出具体的序列是什么)
定义:a[1..n]为原始序列,d[k]表示长度为k的不下降子序列末尾元素的最小值,len表示当前已知的最长子序列的长度。
初始化:d[1]=a[1]; len=1; (0个元素的时候特判一下)
现在我们已知最长的不下降子序列长度为1,末尾元素的最小值为a[1],那么我们让i从2到n循环,依次求出前i个元素的最长不下降子序列的长度,循环的时候我们只需要维护好d这个数组还有len就可以了。
关键问题就是怎么维护?
可以看出我们是要用logn的复杂度维护的。实际上利用了d数组的一个性质:单调性。(长度更长了,d[k]的值是不会减小的)
考虑新进来一个元素a[i]:
如果这个元素大于等于d[len],直接让d[len+1]=a[i],然后len++。这个很好理解,当前最长的长度变成了len+1,而且d数组也添加了一个元素。
如果这个元素小于d[len]呢?说明它不能接在最后一个后面了。那我们就看一下它该接在谁后面。
准确的说,并不是接在谁后面。而是替换掉谁。因为它接在前面的谁后面都是没有意义的,再接也超不过最长的len,所以是替换掉别人。那么替换掉谁呢?就是替换掉那个最该被它替换的那个。也就是在d数组中第一个大于它的。第一个意味着前面的都小于等于它。假设第一个大于它的是d[j],说明d[1..j-1]都小于等于它,那么它完全可以接上d[j-1]然后生成一个长度为j的不下降子序列,而且这个子序列比当前的d[j]这个子序列更有潜力(因为这个数比d[j]小)。所以就替换掉它就行了,也就是d[j]=a[i]。其实这个位置也是它唯一能够替换的位置(前面的替了不满足d[k]最小值的定义,后面替换了不满足不下降序列)
至于第一个大于它的怎么找……STL upper_bound。每次复杂度logn。
至此,我们就神奇的解决了这个问题。按照这个思路,如果需要求严格递增的子序列怎么办?
仍然考虑新进来一个元素a[i]:
如果这个元素大于d[len],直接让d[len+1]=a[i],然后len++。这个很好理解,当前最长的长度变成了len+1,而且d数组也添加了一个元素。
如果这个元素小于等于d[len]呢?说明它不能接在最后一个后面了。那我们就看一下它该接在谁后面。
同样的道理,只是upper_bound的时候要特判一下。每次复杂度logn。
下面是最长不下降子序列的代码
//最长不下降子序列nlogn Song #include<cstdio>#include<algorithm>using namespace std;int a[40005];int d[40005];int main(){ int n; scanf("%d",&n); for (int i=1;i<=n;i++) scanf("%d",&a[i]); if (n==0) //0个元素特判一下 { printf("0\n"); return 0; } d[1]=a[1]; //初始化 int len=1; for (int i=2;i<=n;i++) { if (a[i]>=d[len]) d[++len]=a[i]; //如果可以接在len后面就接上 else //否则就找一个最该替换的替换掉 { int j=upper_bound(d+1,d+len+1,a[i])-d; //找到第一个大于它的d的下标 d[j]=a[i]; } } printf("%d\n",len); return 0;}
想了一晚上这个问题终于想通了。前面说的“最该替换的位置”实际上不是很精确,那个位置替换掉是它唯一能够替换的位置,之所以要替换,就是为了维护d这个数组,让它始终满足最初的定义。
- 最长不下降子序列nlogn算法详解
- 关于最长不下降子序列O(nlogn)算法
- 计蒜客 最长不下降子序列 (nlogn算法)
- 最长不下降子序列的o(nlogn)算法
- 最长不下降子序列 nlogn
- nlogn 最长不下降子序列
- nlogn 最长不下降子序列
- nlogn 最长不下降子序列
- 最长不下降子序列的O(n^2)算法和O(nlogn)算法
- 最长不下降子序列的O(n^2)算法和O(nlogn)算法
- O(NlogN)的最长不下降子序列LIS
- O(nlogn)求最长不下降子序列
- 详解最长不下降子序列
- 最长上升(下降)子序列 O(nlogn)
- hdu4604 最长上升,下降子序列nlogn
- 最长不下降子序列
- 最长不下降子序列
- 最长不下降子序列
- Python socket(TCP阻塞模式)基础程式
- java算法
- LeetCode
- c++数据结构:线性表实现之双链表
- 51nod 1323 完美平方
- 最长不下降子序列nlogn算法详解
- cookie和session
- 关于过载控制
- UML学---类图
- 算法笔记 //06_集合划分问题
- 简单线性回归及实现
- C语言数据类型那点事
- 搭建hbase的完全分布式模式
- FileInputStream和FileOutputStream实现简单的文件复制