最长上升子序列

输入一个序列,求最长上升子序列(LIS)。

小数据

输入

    第1行:1个整数n(1<=n<=5000),表示序列中元素的个数.

    第2行-n+1行:每行1个整数x(-1000<=x<=1000),第i+1行表示序列中的第i个元素。

输出

    第1行:1个整数k,表示最长上升子序列的长度。

思路:

    深搜是行不通的,广搜也是行不通的,两者的时间复杂度都很高,前者是n的阶乘,后者要爆。

所以只能以逆向的思维,用记忆化搜索——动态规划(DP)来做,时间复杂度为O( n * ( n + 1 ) / 2 )。

    DP主要就是利用数组里的部分最优解来求出另一个解,每个元素都要互相调用,调用的元素都是之前计算过的,当然也可以用递归优化。这就是它的本质——记忆化递归。

    这里用一个数组 f [  ],f [ i ] 记录从1号元素到 i 号元素之间,以 i 元素结尾的最长上升子序列的长度,相当于它每一个元素就是一个可以独立输出的解了!

    跟递推式一样,DP也有一个求解的式子(叫状态转移方程),可以代入求每一个 f [ i ]。这道题的式子是这样的:

f [ i ] = min ( f [ 1 ] , f [ 1 ] , ... , f [ i - 1 ] ) + 1

    代码也很简单:(为了防复制我就发截图)

还没懂的可以看大神的解说:[ 点这里 ]

大数据

【题目背景】

    进步,就是爬坡。——某不愿透露姓名高调路过的吃瓜群众。

    高度迥异的坡很多,而你想进步。

输入

    第一行一个正整数 n (1<=n<=100000),表示有n个坡。

    第二行n个正整数ai(ai<=1e9),表示每个坡的高度。

输出

    一行,一个正整数,表示最长的上升子序列(LIS)。

思路:

    前面已经提到过,

用记忆化搜索——动态规划(DP)来做,时间复杂度为O( n * ( n + 1 ) / 2 )

这次的数据很大了,用前面的方法不再可靠了。为了减小时间复杂度,要么把他降成O( n ),要么降成O( n logn )。

所以就要用一种可以配合二分的数据结构——单调栈。具体做法如下:

开一个栈(数组模拟),将a[0]入栈,每次取栈顶元素top和读到的元素a[i](0<i<n)做比较,如果a[i]> top 则将a[i]入栈;如果a[i]<= top二分查找栈中的比a[i]大的第1个数,并用a[i]替换它。 最长序列长度即为栈的大小top。这是很好理解的,对于xy,如果x < ystack[y] < stack[x],用stack[x]替换stack[y],此时的最长序列长度没有改变,但序列继续变长的''潜力''增大了。

举例:原序列为158367开始158相继入栈,此时读到3,用3替换5得到1,3,8; 再读6,用6替换8,得到1,3,6;再读7,得到最终栈为1,3,6,7。最长递增子序列为长度4。

…………

 

代码:

posted @ 2018-12-07 14:20  DD_XYX  阅读(66)  评论(0编辑  收藏  举报