最长上升子序列的nlogn算法实现(用栈)

最长上升子序列的nlogn算法实现(用栈)

大体算法思想是设置一个栈,数据结构里严格意义上的栈是后进先出,但是这里的栈中间有稍微不一样的地方在于中间的元素也会被覆盖掉,算法过程是,第一个元素入栈,以后没读取一个元素t,如果t比栈顶元素的大,那么就入栈。如果比它小,那么就用二分搜索的方法在栈里面找到这样一个元素stack[i],使得stack[i]>t并且stack[i-1](如果有的话)<t,然后就用t去更新这个stack[i]元素。举个例子,如果输入一下数据

5 9 4 1 3 7 6 7

那么栈的变化过程为:

5
5 9
4 9 //用4更新了5
1 9
1 3
1 3 7
1 3 6
1 3 6 7

最后的结果,最长递增子序列的长度就是栈的大小,这里是4。要注意的是最后栈里的元素并不就一定是所求的序列,例如如果输入

2 5 1

那么最后得到的栈应该是

1 5

而实际上要求的序列是

2 5

至于要怎么求这个序列。。。这个。。。看了讲解之后自己还是没研究透彻。。。哈哈,有空再说了。算法的正确性没有经过严格的证明,不过想想看应该是对的吧,哈哈,偷懒了。

代码(写得有些丑陋的):

/*
习题 33:最长递增子序列★★★

问题描述:
所谓子序列,就是在原序列里删掉若干个元素后剩下的序列,以字符串"abcdefg"为例子,去掉bde得到子序列"acfg"
现在的问题是,给你一个数字序列,你要求出它最长的单调递增子序列。

输入:
多组测试数据,每组测试数据第一行是n(1<=n<=10000),下一行是n个比1e9小的非负整数

输出:
对于每组测试数据输出一行,每行内容是最长的单调递增子序列的长度

样例输入:
5
1 2 4 8 16
5
1 10 4 9 7
9
0 0 0 1 1 1 5 5 5

样例输出:
5
3
3

难度:normal
*/
#include <cstdio>

#define MAXN 10000
long long stack[MAXN];
int n;
long long t;
int top;

int main()
{
    int i;
    int mid,high,low;
    while(scanf("%d",&n)==1 && n!=0)
    {
        scanf("%lld",&stack[0]);
        top=1;
        for(i=1;i<n;i++)
        {
            scanf("%lld",&t);
            if(t>stack[top-1])                             //一
                stack[top++]=t;
            if(t==stack[top-1])                          //二
                continue;
            else                                               //三
            {
                low=0;
                high=top-1;
                while(true)
                {
                    mid=(low+high)/2;
                    if(stack[mid]>=t && (mid==0 || stack[mid-1]<t))
                    {
                        stack[mid]=t;
                        break;
                    }
                    if(stack[mid]<t)
                        low=mid+1;
                    else
                        high=mid-1;
                }
            }
        }
        printf("%d\n",top);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值