单调递增最长子序列
时间限制:
3000 ms | 内存限制:
65535 KB
难度:
4
-
描述
-
求一个字符串的最长递增子序列的长度
如:dabdbf最长递增子序列就是abdf,长度为4-
输入
-
第一行一个整数0<n<20,表示有n个字符串要处理
随后的n行,每行有一个字符串,该字符串的长度不会超过10000
输出
- 输出字符串的最长递增子序列的长度 样例输入
-
3 aaa ababc abklmncdefg
样例输出
-
1 3 7
来源
- 经典题目 上传者
思路:
题目不难,若能灵活应对的情况下...
在全为字母的情况下,求单调递增最长子序列,结果最大值就是26.因为就26个字母! 因此从前向后遍历,我们找到('a'...s[i])中的最长递增子序列的长度,它出现的长度加1就是(1..i)中比s[i]小的递增子序列长度.
还有一个更为巧妙的方法,虽然不是最优,就是作用最长公共子序列.只要将其中一个序列固定为'a...z',它与其它序列的最长公共子序列即为最长递增子序列.
代码1:
#include <stdio.h> #include <string.h> #define N 10005 char s[N]; int dp[30]; int main() { int loop; scanf("%d", &loop); while(loop --){ scanf("%s", s); int len = strlen(s); memset(dp, 0, sizeof(dp)); int MaxN = 0; for(int i = 0; i < len; i ++){ int ls = 0; for(int j = 0; j < s[i] - 'a'; j ++){ if(dp[j] > ls) ls = dp[j]; } dp[s[i] - 'a'] = ls + 1; if(MaxN < dp[s[i] - 'a']) MaxN = dp[s[i] - 'a']; } printf("%d\n", MaxN); } return 0; }
代码2(最长公共子序列改):
#include <stdio.h> #include <string.h> #define N 10001 int lcs[30][N]; int max(int a, int b){ return a > b ? a : b; } int main() { int n, i, j; char x[40] = {"abcdefghijklmnopqrstuvwxyz"}; char y[N]; scanf("%d", &n); while(n --){ scanf(" %s", y); int lenx = strlen(x); int leny = strlen(y); for(i = 0; i <= lenx; i ++) lcs[i][0] = 0; for(i = 1; i <= leny; i ++) lcs[0][i] = 0; for(i = 1; i <= lenx; i ++){ for(j = 1;j <= leny; j ++){ lcs[i][j] = (x[i - 1] == y[j - 1]) ? (lcs[i - 1][j - 1] + 1) : max(lcs[i - 1][j], lcs[i][j - 1]); } } printf ("%d\n", lcs[lenx][leny]); } return 0; }
-
第一行一个整数0<n<20,表示有n个字符串要处理