单调递增最长子序列
-
描述
-
求一个字符串的最长递增子序列的长度
如:dabdbf最长递增子序列就是abdf,长度为4-
输入
-
第一行一个整数0<n<20,表示有n个字符串要处理
随后的n行,每行有一个字符串,该字符串的长度不会超过10000
输出
- 输出字符串的最长递增子序列的长度 样例输入
-
3 aaa ababc abklmncdefg
样例输出
-
1 3 7
-
第一行一个整数0<n<20,表示有n个字符串要处理
#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 则不能增加长度,题意又要求是最长子序列,所以用这个是合适,然而在查找的时候用二分法,又是最省时间的,高效!!!
我的表达能力不好,如果大家看了有什么不懂的话,就评论给我,欢迎质疑!!!