研发岗-第一题-最长k阶完美子序列
题目内容
给定一个只含小写字母的字符串\(s\), \(k\)阶完美子序列\(t\)的定义是:\(t\)是字符串\(s\)的一个子序列.并且\(t\)中任意一个相邻的字符在字符表中距离相差不过kk.现在塔子哥需要你求出最长的k阶完美子序列
说明:
- 1.字符串的子序列同样是一个字符串,并且子序列还满足:可以经由字符串删除某些字符(也可以不删除)但不改变剩余字符的顺序得到。
- 2.字符表的距离是不循环的,即aa 和 zz 的距离是2525 而不是11
输入描述
每行输入一个字符串\(s\)和一个整数\(k\)
\(|s| \leq 10^5 , 0 \leq k \leq 25\)
输出描述
输出为整数nn,代表字符串ss的最长kk阶完美字符串长度
示例1
输入
bcda 1
输出
3
说明:bcd是一个合法的最长序列,长度为3
示例2
输入
abbccd 0
输出
2
说明:bb/cc是一个合法的最长序列.长度为2
题解:
定义f[i][j]表示前i个字母以字母j结尾的最长子序列长度对于前i个字母
- 如果不选择第i个字母,则对于任意0≤j≤25,都有f[][j]= f[i-1][j]
- 如果选择第i个字母,先把当前字母映射到\([0,25](x=s[i]-'a')\),然后开始枚举所有\(x-k<=j<=s+k\)
更新\(f[i][j]=max(f[i][j],f[i―1][j]+1)\)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 100010;
int k;
int s[N];
int f[N][26];//在前i个字符串当中,以j为结尾的最长子序列长度
void solve(){
string str;
cin>>str>>k;
int n = str.size();
for(int i = 0;i<n;i++){
s[i+1] = str[i]-'a';
}
for(int i = 1;i<=n;i++){
for(int j = 0;j<=25;j++)f[i][j] = f[i-1][j];
int l = max(s[i]-k,0),r = min(s[i]+k,25);
for(int j = l;j<=r;j++){
f[i][s[i]] = max(f[i-1][j]+1,f[i][s[i]]);
}
}
int ans = 0;
for(int i = 1;i<=n;i++){
for(int j = 0;j<=25;j++){
ans = max(ans,f[i][j]);
}
}
cout<<ans<<"\n";
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
solve();
}