单调递增最长子序列
时间限制:3000 ms | 内存限制:65535 KB
难度:4
- 描述
- 求一个字符串的最长递增子序列的长度
如:dabdbf最长递增子序列就是abdf,长度为4
- 输入
- 第一行一个整数0<n<20,表示有n个字符串要处理
随后的n行,每行有一个字符串,该字符串的长度不会超过10000 - 输出
- 输出字符串的最长递增子序列的长度
- 样例输入
-
3 aaa ababc abklmncdefg
- 样例输出
1 3 7
- 本题有多种解法:
- 一:最长公共子序列法
- 此方法用时较长,占用内存也较大,且仅适用于有规律且有限长度的子序列中,代码如下:
#include<stdio.h> #include<string.h> #define max(a,b) (a>b?a:b) int dp[10010][30]; int main(void) { char a[10010]; char b[30]={'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'}; int n,len,i,j,k; int sum,max; scanf("%d",&n); while(n--) { scanf("%s",a); len=strlen(a); for(i=1;i<=len;i++) { for(j=1;j<=26;j++) { if(a[i-1]==b[j-1]) { dp[i][j]=dp[i-1][j-1]+1; } else { dp[i][j]=max(dp[i-1][j],dp[i][j-1]); } } } /* for(i=0;i<len;i++) { for(j=0;j<26;j++) { printf("%d ",dp[i][j]); } printf(" "); } */ printf("%d ",dp[len][26]); } return 0; }
二:O(n^2) 最大子段和法
此方法采用了标记数组,记录每个当前状态下的最优解。
本题中的核心代码就是那两个for循环来更新m和dp数组中的值,
其中第一个循环中,每次都须将m置零 ,
其中第二个for循环的意思就是更新m的值,
使m的值为i位置字符之前的所有比i位置字符小的dp数组中所存值得最大值,直至第二个循环
结束,使i位置的dp数组为m的值加上1,即可。
代码如下:
#include<stdio.h> #include<string.h> char s[10010]; int dp[10010]={1}; int main(void) { int n,len; int i,j,m; scanf("%d",&n); while(n--) { scanf("%s",s); len=strlen(s); for(i=1;i<len;i++) { m=0; for(j=i-1;j>=0;j--) { if(s[i]>s[j]&&m<dp[j]) { m=dp[j]; } } dp[i]=m+1; } m=dp[0]; for(i=0;i<len;i++) { if(m<dp[i]) { m=dp[i]; } } printf("%d ",m); } return 0; }
三:O(n^2) 此方法是方法二的优化,方法二中的标记数组过长,此方法采用标记字符串,所以标记数组的长度缩减到26即可,本代码中用的长度为30
本题中使用了标记字符串,先将待求字符串中的第一个字符赋到标记字符串中,
并使用k对标记字符串进行计数,
然后依次读入待求字符串的字符,
并与标记字符串中的字符从后往前依次比较,
若标记字符串的字符比待求字符串的字符大,且此时处在标记字符串的起始位置
,则将此位置的待求字符赋到标记字符串中,
若标记字符串的字符比待求字符串的字符小,则将此处待求字符串的字符赋到标记字符串的下一个字符,如果此时已达到标记字符串的长度,则令k加1,并结束当前循环,重新开始比较,重新开始时,只有k增加了一,其余各数据均不变。
代码如下:
#include<stdio.h> #include<string.h> int main(void) { char s[10010]; char dp[35]; int n,len,i,j,k; scanf("%d",&n); while(n--) { scanf("%s",s); len=strlen(s); dp[0]=s[0]; k=1; for(i=0;i<len;i++) { for(j=k-1;j>=0;j--) { if(dp[j]>s[i]&&j==0) { dp[0]=s[i]; } if(dp[j]<s[i]) { dp[j+1]=s[i]; if(j==k-1) { k++; } break; } } } dp[k]='