题目信息:
单调递增最长子序列
时间限制:3000 ms | 内存限制:65535 KB
难度:4
- 描述
- 求一个字符串的最长递增子序列的长度
如:dabdbf最长递增子序列就是abdf,长度为4- 输入
- 第一行一个整数0<n<20,表示有n个字符串要处理
随后的n行,每行有一个字符串,该字符串的长度不会超过10000 输出 - 输出字符串的最长递增子序列的长度 样例输入
-
3 aaa ababc abklmncdefg
样例输出 -
1 3 7
- 第一行一个整数0<n<20,表示有n个字符串要处理
动态规划的最长子序列问题,有两种解法,一种比较好理解,就是动态规划数组存当前每一个能存的最大值,求最大值时从后往前找,找到能接上且最大的值,令它加一即是当前最长子序列长度,最后再在动态规划数组中找最大值即可。另一种LIS解法降低了空间复杂度,并可以直接求出来最长子串,这种解法的动态规划数组存的直接是字符的ASCII码值(也可以用char类型数组直接存字符),逐位判断字符:从后向前查找到数组中小于当前字符的目标,用当前字符覆盖目标的后一位,如果加入的位置是数组末尾,则长度加一。
代码部分:
#include <stdio.h>
#include <string.h>
int main()
{
int n,i,j,len,count;
char s[10005];
int dp[10005];
scanf("%d",&n);
while(n--)
{
memset(dp,0,sizeof(dp));
count=0;
scanf("%s",s);
len=strlen(s);
for(i=0;i<len;i++)
{
for(j=i-1;j>=0;j--)
{
if(dp[i]<=dp[j]&&s[i]>s[j])
{
dp[i]=dp[j];
}
}
dp[i]++;
if(count<dp[i])
count=dp[i];
}
printf("%d\n",count);
}
return 0;
}
LIS解法:
#include <stdio.h>
#include <string.h>
int main()
{
int n,i,j,count;
char s[10005];
int dp[30];
scanf("%d",&n);
while(n--)
{
memset(dp,0,sizeof(dp));
scanf("%s",s);
count=0;
for(i=0;i<strlen(s);i++)
{
for(j=count;j>=0;j--)
{
if(s[i]>dp[j])
{
dp[j+1]=s[i];
if(j==count)
count++;
break;
}
}
}
printf("%d\n",count);
}
return 0;
}
C++ lower_bound:
int dp[MAX_N];
void solve()
{
fill(dp, dp + n, INF);
for(int i = 0; i < n ; i++)
*lower_bound(dp, dp + n, a[i]) = a[i];
printf("%d\n", lower_bound(dp, dp + n, INF) - dp);
}