nyoj 17 单调递增最长子序列

来源:互联网 发布:中国银行控件mac 编辑:程序博客网 时间:2024/05/29 19:32

单调递增最长子序列

时间限制:3000 ms  |  内存限制:65535 KB
难度:4
描述
求一个字符串的最长递增子序列的长度
如:dabdbf最长递增子序列就是abdf,长度为4
输入
第一行一个整数0<n<20,表示有n个字符串要处理
随后的n行,每行有一个字符串,该字符串的长度不会超过10000
输出
输出字符串的最长递增子序列的长度
样例输入
3aaaababcabklmncdefg
样例输出
137

#include<stdio.h>
#include<string.h>
int main()
{
    int n,h;scanf("%d",&n);getchar();
    while(n--)
    {
    
    char s[10001];
    gets(s);
    int a[10001]={0},i,j;      //原理:a【i】的值,记录着是以第i个元素结尾的字符串的长度
    h=strlen(s);
    for(i=0;i<h;i++)
    {
        for(j=0;j<=i;j++)
        {
            if(s[j]<s[i]  && a[j]>=a[i])//如果不加后面判断的话,那么就会出错,如下:
            a[i]=a[j]+1;               //bcbcfbk这个例子,a【i】是一直变化的,如果i遍历到b时,j到f时,a【b】=0
                                        //当i遍历到k,j遍历到f时,a【i】变化为3,而j遍历到b时,a【j】=a【b】<a[i],所以在这种情况下,答案是错误的

        }
    }
    
    int max=a[0];
    for(i=0;i<h;i++)
    {
        if(max<a[i])
        max=a[i];//找最大值,最高的山峰
    }
    printf("%d\n",max+1);    //开始从0开始,所以要加一
    }
    
    return 0;
}


还有一种优化后的解法:就是利用二分法

       例如:defcda 

用学长说的,自己命名为山峰法,从第一位字母遍历

第一位:记录    d

第二位:记录    d  e

第三位:记录   d   e  f         //前两位都是后面一位大于它,所以直接增加一个元素

第四位:记录   c   e  f         //因为c在d的前面,所以将d替换为 c

第五位:记录   c   d  f         //d在e前面,c后面,所以把e替换为d

第六位:记录   a   d  f          //因为a在c 前面,所以把c替换成a

则    最后的结果为  a d f   的长度为   3.

       大家一定感觉有点突兀吧,接下来听听为啥把?

每遍历一个元素,就用它和最后一位元素比较,如果大于则增加长度,如果小于的话,没必要增加长度,但是要把最接近这个元素且大于这个元素的元素给换掉,那么为什么换掉呢,大家想想看,如若是将 x y z 这个字符串一步一步换成 a b c 的话,a b c 还有可能继续增加长度,而 x y z 则不能增加长度,题意又要求是最长子序列,所以用这个是合适,然而在查找的时候用二分法,又是最省时间的,高效!!!

      我的表达能力不好,如果大家看了有什么不懂的话,就评论给我,欢迎质疑!!!

 
0 0
原创粉丝点击