单调递增最长子序列
-
描述
-
求一个字符串的最长递增子序列的长度
如:dabdbf最长递增子序列就是abdf,长度为4-
输入
-
第一行一个整数0<n<20,表示有n个字符串要处理
随后的n行,每行有一个字符串,该字符串的长度不会超过10000
输出
- 输出字符串的最长递增子序列的长度 样例输入
-
3 aaa ababc abklmncdefg
样例输出
-
1 3 7
来源
- 经典题目 上传者
这个题我用了两种方法,都算是动态递归吧,
第一种是LCS的方法,一开始没想到用字母表拿26个作为另一个串,懵逼了半天
这种方法就参照LCS的解法就行
# include <stdio.h>
# include <iostream>
# include <string.h>
using namespace std;
# define SIZE 10500
char alphabet[28] = "Aabcdefghijklmnopqrstuvwxyz";
char str[SIZE];
int dp[30][SIZE];//数组一定要开得比实际数据大一点 我一开始就是忘了改这里的dp数组 导致改了很久很久的错误
int LCS(int m, int n)
{
//m是字母表的长度, n是输入的字符串的长度//这个算法今天算是彻底把他弄明白记住了,又多了一分把握
int i, j;
for(i = 0; i <= m; i++)
for(j = 0; j <= n; j++) dp[i][j] = 0;
for(i = 1; i <= m; i++){
for(j = 1; j <= n; j++){
if(alphabet[i] == str[j]) dp[i][j] = dp[i-1][j-1] + 1;
else if(dp[i-1][j] >= dp[i][j-1]) dp[i][j] = dp[i-1][j];
else dp[i][j] = dp[i][j-1];
if(dp[i][j] >= 26){
dp[m][n] = 26;
return 0;
}
}
}
return 0;
}
int main()
{
int N, len1, len2, i;
freopen("in.txt","r",stdin);
len2 = 27;
scanf("%d", &N);
while(N--){
scanf("%s", str);
len1 = strlen(str);
for(i = len1-1; i >= 0; i--)
str[i+1] = str[i];
LCS(len2, len1);
printf("%d\n", dp[len2][len1]);
}
return 0;
}
第二种方法我也不知道叫个什么名字,反正大概思路就是通过去分解每一个子问题,找到每个子问题的最大解,然后求出最终解
#include<iostream>
#include<string.h>
#include<stdio.h>
using namespace std;
//动态规划
//这种思想就是倒过来看 看每一个字符能大于前面多少个字符。
char str[10005];//存储字符串
int num[10005];//存储前i位字符串中最长递增子序列的长度
int main()
{
int N, max_len, len, i, j, flag, Max;//N组数据
freopen("in.txt", "r", stdin);
scanf("%d",&N);
while(N--)
{
memset(str,'\0',sizeof(str));
memset(num,0,sizeof(num));
scanf("%s",str);
max_len=0;//记录最大长度
len=strlen(str);
num[0]=1;
Max = 0;
for(i=1; i<len; i++)
{
flag=0;
for(j=0; j<i; j++)
{//发现一个字符小于 i 字符, 并且比上一次小于 i 字符的更小,也就是说能形成递增序列。
if(str[i]>str[j]&&flag<num[j])
flag=num[j];
}
num[i]=flag+1;//这里就是为了节约时间 因为字母表只有26个 所以最大值是26 当出现最大值了就没必要再继续计算下去
if(num[i] >= 26){
Max = 1;
break;
}
}
if(Max) printf("26\n");
else
{
for(i=0; i<len; i++)
max_len=max(max_len,num[i]);
printf("%d\n",max_len);
}
}
return 0;
} -
第一行一个整数0<n<20,表示有n个字符串要处理