最长上升子序列

时间限制: 10 Sec   内存限制:128 MB

题目描述

给定一个序列,初始为空。现在我们将1到N的数字插入到序列中,每次将一个数字插入到一个特定的位置。我们想知道此时最长上升子序列长度是多少?

输入

第一行一个整数N,表示我们要将1到N插入序列中,接下是N个数字,第k个数字Xk,表示我们将k插入到位置Xk(0<=Xk<=k-1,1<=k<=N)

输出

1行,表示最长上升子序列的长度是多少。

样例输入

3

0 0 2

样例输出

2

提示

100%的数据 n<=100000

O(nlogn)算法代码

 #include <iostream>
using namespace std;
int i,j,n,s,t,a[];
int main()
{
cin>>n;
a[]=-;
for(i=;i<n;i++)
{
cin>>t;/* 比栈顶元素大数就入栈 */
if(t>a[s]) a[++s]=t;
else
{
int l=,h=s,m;
/* 二分检索栈中比t大的第一个数 */
while(l<=h)
{
m=(l+h)/;
if(t>a[m]) l=m+;
else h=m-;
}/* 用t替换 */
a[l]=t;
}
}/* 最长序列数就是栈的大小 */
cout<<s<<endl;
}

代码分析:

第一个念头就是用动态规划,很显然,这道题的转移方程非常非常简单,一目了然,先准备一个数组b

b[i]=1;
,从a[1]开始搜到i的最长上升子序列。

这句赋值语句固然很好理解,每一个元素,也可以视为一个符合题意的子序列。

b[2]呢?

如图,它显然比a[1]高,在执行如下语句时

for(j=1;j<i;j++)  
if(a[i]>a[j])

j小于i,也就是2,目前符合条件的只有a[1]a[1]又通过了判断语句,它确实小于a[i],执行下一条语句:

b[i]=max(b[i],b[j]+1);

很显然:b[2]显然原来是1,当它和b[1]+1比时,1当然比2小,所以,b[2]自然就是2了。

再来看看时间复杂度:

很明显,时间复杂度为O(n^2)


那,这个方法够快吗?还可以,但仍然有些不尽人意。

代码如下O(n^2):

 #include<iostream>
using namespace std;
int i,j,n,a[],b[],max;
int main()
{
cin>>n;
for(i=;i<n;i++) cin>>a[i];
b[]=; //初始化,以a[0]结尾的最长递增子序列长度为1
for(i=;i<n;i++)
{
b[i]=;//b[i]最小值为1
for(j=;j<i;j++)
if(a[i]>a[j]) b[i]=max(b[i],b[j]+);
}
for(max=i=;i<n;i++) if(b[i]>max) max=b[i];
cout<<max<<endl;
}

那么,还有没有更快的方法呢?

当然有,有没有想到过,为什么要记录数据呢?

我们可以模拟一个stack

在有大量数据的情况下,这算法效率极高

但是,怎么来优化程序呢?

我们可以这样来模拟:

每输入一个数,如果这个数大于栈顶的那个数,于是把它推入栈中。

但是,如果这个数大于栈顶呢,这不证明它不可以更新栈中的

某个元素,这时,就可以运用二分查找了。

     有人可能会问:这个序列是无序的啊。没错,但查找的是stack里面的元素,而这个栈里的所有元素,都是严格递增的,所以,用二分查找可以把问题缩减为O(nlogn)

     有些不符合逻辑,不是吗?15的下标比171820都大,为什么能插入呢?但是如果仔细想一想,这好像并不影响正常答案,但如果要输出最长上升子序列,那就要改一改这个算法了。

整个二分查找代码如下:

else

{

    int l=1,h=s,m;

    while(l<=h)

    {

         m=(l+h)/2;

         if(t>a[m]) l=m+1;

         else h=m-1;

    }

    a[l]=t;

}

由此,这个查找算法才得以下降到logn,于是,整体也就是O(nlogn)

具体操作如下:

每次取栈顶元素和读到的元素做比较,如果大于,则将它入栈;如果小于,则二分查找栈中的比它大的第1个数,并替换它。最长序列长度即为最后模拟的大小。

这也是很好理解的,对于ij,如果i <ja[i] < a[j],a[i]替换a[j],长度虽然没有改变但a'潜力'增大了。

代码(同上):

 #include <iostream>
using namespace std;
int i,j,n,s,t,a[];
int main()
{
cin>>n;
a[]=-;
for(i=;i<n;i++)
{
cin>>t;
if(t>a[s]) a[++s]=t;
else
{
int l=,h=s,m;
while(l<=h)
{
m=(l+h)/;
if(t>a[m]) l=m+;
else h=m-;
}
a[l]=t;
}
}
cout<<s<<endl;
}

最长上升子序列O(nlogn)算法详解的更多相关文章

  1. 最长不下降子序列nlogn算法详解

    今天花了很长时间终于弄懂了这个算法……毕竟找一个好的讲解真的太难了,所以励志我要自己写一个好的讲解QAQ 这篇文章是在懂了这个问题n^2解决方案的基础上学习. 解决的问题:给定一个序列,求最长不下降子 ...

  2. (转载)最长递增子序列 O(NlogN)算法

    原博文:传送门 最长递增子序列(Longest Increasing Subsequence) 下面我们简记为 LIS. 定义d[k]:长度为k的上升子序列的最末元素,若有多个长度为k的上升子序列,则 ...

  3. 最长递增子序列 O(NlogN)算法

    转自:点击打开链接 最长递增子序列,Longest Increasing Subsequence 下面我们简记为 LIS. 排序+LCS算法 以及 DP算法就忽略了,这两个太容易理解了. 假设存在一个 ...

  4. NOIP200407合唱队形+最长上升子序列O(n^2)详解

    合唱队形解题报告 2016-05-12   4:30——6:45 NOIP200407合唱队形 难度级别:A: 运行时间限制:1000ms: 运行空间限制:256000KB: 代码长度限制:20000 ...

  5. 最长递减子序列(nlogn)(个人模版)

    最长递减子序列(nlogn): int find(int n,int key) { ; int right=n; while(left<=right) { ; if(res[mid]>ke ...

  6. 洛谷1439:最长公共子序列(nlogn做法)

    洛谷1439:最长公共子序列(nlogn做法) 题目描述: 给定两个序列求最长公共子序列. 这两个序列一定是\(1\)~\(n\)的全排列. 数据范围: \(1\leq n\leq 10^5\) 思路 ...

  7. 洛谷 [p1439] 最长公共子序列 (NlogN)

    可以发现只有当两个序列中都没有重复元素时(1-n的排列)此种优化才是高效的,不然可能很不稳定. 求a[] 与b[]中的LCS 通过记录lis[i]表示a[i]在b[]中的位置,将LCS问题转化为最长上 ...

  8. 算法进阶面试题01——KMP算法详解、输出含两次原子串的最短串、判断T1是否包含T2子树、Manacher算法详解、使字符串成为最短回文串

    1.KMP算法详解与应用 子序列:可以连续可以不连续. 子数组/串:要连续 暴力方法:逐个位置比对. KMP:让前面的,指导后面. 概念建设: d的最长前缀与最长后缀的匹配长度为3.(前缀不能到最后一 ...

  9. BM算法  Boyer-Moore高质量实现代码详解与算法详解

    Boyer-Moore高质量实现代码详解与算法详解 鉴于我见到对算法本身分析非常透彻的文章以及实现的非常精巧的文章,所以就转载了,本文的贡献在于将两者结合起来,方便大家了解代码实现! 算法详解转自:h ...

随机推荐

  1. 【C++】函数指针宏定义

    看耗子叔文章学习虚函数表(http://blog.csdn.net/haoel/article/details/1948051)的时候被例子的第一句惊到了 typedef void(*Fun)(voi ...

  2. 删除Checkout with Multiple Addresses

    如果选择No,您的客户在结账时只可以输入一个收货地址,订单的货物都会送到这个地址.如果您选择Yes,您的客户将可以选择发货到多个地址,在购物车中的Proceed to Checkout按钮下面将会出现 ...

  3. Tea---hdu5881(规律)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5881 题意: 现在有一壶水,体积在[L, R]范围内,现有两个空杯子,现想要把这壶水倒入这两个杯子中去 ...

  4. cannot open /proc/bus/usb/devices, No such file or directory

    由于kernel config中没有打开对应的配置. make menuconfig 选择: Device Drivers ---> [*] USB support ---> [*] US ...

  5. linux matlab2013b 安装教程

    链接:http://pan.baidu.com/s/1pJE6R2b 密码:shfy 1. 解压缩“Mathworks Matlab R2013b Linux.rar”(无需密码),得到“Mathwo ...

  6. nohup和&的区别

    nohup和&的区别http://bbs.chinaunix.net/forum.php?mod=viewthread&tid=4241330&fromuid=21288388 ...

  7. C#开发ActiveX插件-aspx中嵌入

    刚到新的公司,第一周让我熟悉一下他们用的silverlight和arcgis.这周,也就是昨天分配了我一个小小的任务! 哪个项目的不知道,是让我实现一个在aspx中嵌入activeX插件! 在网上找了 ...

  8. Aws api gateway Domain name

    Set Up a Custom Domain Name for an API Gateway API The following procedure describes how to set up a ...

  9. 帮你深入理解OAuth2.0协议

    1. 引言 如果你开车去酒店赴宴,你经常会苦于找不到停车位而耽误很多时间.是否有好办法可以避免这个问题呢?有的,听说有一些豪车的车主就不担心这个问题.豪车一般配备两种钥匙:主钥匙和泊车钥匙.当你到酒店 ...

  10. 查看docker中container的ip

    使用命令 docker inspect 容器ID 然后过虑出 IPAddress 即可查看 Docker 的 IP docker inspect 容器ID | grep IPAddress