【DP】——求最长有序子序列(不要求连续)

 【关注一下】http://www.seayar.tk

【简介】
最长有序子序列(不要求连续),顾名思义,就是一个序列中,在给你的一个序列中找个子序列,要求是有序的(要么单调递增,要么单调递减)。这是一个很经典的动态规划问题,所以记录下来以作日后复习用,顺便与各位同道共享。

先说个定义吧,对于一个序列X[N]={a[1],a[2],....,a[n]},如果存在一个序列Z={b[1],b[2],..,b[k]},其中Z中的各个元素属于X,并且b[1]<b[2]<...<v[k],那么就是序列Z的一个有序子序列,那么也就是说,这个问题就是在众多的组合中,寻找一种可行的最长的有序的子序列。

煮个栗子吧, 有一个序列{1,3,2,6},那么它的有序子序列有以下几种情况(不算空集合):
{1}、{3}、{2}、{6};
{1,3}、{1,2}、{1,6}、{1,2}、{1,6}、{3,6}、{2,6};
 {1,3,6}、{1,2,6};
但是如果要求是最长的,那就是{1,3,6}或者{1,2,6}。

【算法分析】
那这种问题如果用一般的组合方法一个个遍历求解的话,需要多大的时间开销呢?对,是C(1,n)+C(2,n)+..+C(n,n),是2^n种情况,那就是这种算法的时间复杂度是O(2^n),指数级的时间复杂度啊有木有!!这样的程序很可能是TLE啊有木有!!

那DP的话能换成多大的时间开销呢?DP一般把时间复杂度控制在多项式时间内,而这个问题用DP解,它的时间复杂度是:O
(n^2),这是我们可以接受的范围内的~~

那么,下面来说说这个算法的基本思路:
(1)、DP一般需要辅助数组来记录之前出现过的某些子问题的最优解,这道题也是一样的,需要两个数组来记录,一个用来记录最优解的位置,另一个用来记录个状态的最优解。设posotion[]记录位置,record[]记录最优解。此外我们增加一个maxNow的变量用于记录当前最长的长度。data[]是原始输入数据。
(2)、现在是写状态转移方程的时候了,我们可以来分析一下,对于第i个状态,我们可以查找前i-1个子问题的最优解,record[i]=max(record[k])+1(data[k]<data[i]),即保持单调递增;在这种情况下如果record[i]大于当前最长长度maxNow,那么就更新maxNow,maxNow+=1;
(3)
若maxNow更新了,那它前一个状态的位置记录下来就是position[i]=k;即第k个元素是它的前一个元素,当前位置用一个positionNow记录,那么positionNow=i,最后输出的时候反序输出就OK。

【算法改进】
其实在找max(record[k])会花费大量的时间,所以可以改进一下储存格式然后用二分查找的方法,具体内容等我慢慢参透了然后再记录下来吧!总之可以把时间复杂度缩减到 
O(nlogn)! 

posted @ 2013-05-07 15:24  seayar  阅读(794)  评论(0编辑  收藏  举报