题目信息
对于字符串s,有些同学经常搞混 子串 和 子序列:
子串:s中连续的一段字符,例如"abc"的子串有{a,b,c,ab,bc,abc,空}等
子序列:s中相对顺序不变的一段字符,例如"abc"的子序列有{a,b,c,ab,ac,bc,abc,空}等
题目描述
现在给定字符串A,B,请你删除B串的一个最短子串,使B串成为A串的一个子序列。
答案可能为0,即B本身就是A的一个子序列;答案也可能为lenB,即需要将B删成空串。
输入格式
第一行1个整数t,代表输入方式
若t = 0: 输入2行,分别为字符串A,B
若t = 1: 输入2行,每行4个非负整数{c1, a, b, n},用以下方式自行生成A串和B串:
long long c[MAXN];
char str[MAXN];
c[1] = c1;
for i = 2 to n:
c[i] = (c[i-1]*a + b) % P;
for i = 1 to n:
str[i] = 'a' + c[i]%26
其中模数P = 1e9+7
输出格式
一个整数,代表所需要删除的最短子串长度
输入输出样例
输入 #1
0
im
ran
输出 #1
3
输入 #2
0
abca
accepted
输出 #2
6
输入 #3
0
abacaba
aa
输出 #3
0
输入 #4
1
0 2 3 15
0 4 5 5
输出 #4
1
说明/提示
对于样例4,A串/B串为:
adjvtphrlzbfndj
afzbj
- 对于20%的数据,字符串长度<=20
- 对于40%的数据,字符串长度<=200
- 对于60%的数据,字符串长度<=2000
- 对于80%的数据,字符串长度<=1e5
- 对于100%的数据,字符串长度<=1e7,输入保证仅包含小写字符,若字符串长度<=2000则有tp=0,否则有tp=1;a,b<=1e9
解题思路
法1:二分+判断子序列(60pts)
二分删除的最小长度,然后枚举所有这个长度的B的子串判断是否为A的子序列。
时间复杂度:O(n2logn)(二分:logn 枚举子串:O(n) 双指针判断子序列:O(n))
空间复杂度:O(n)
法2:递推(正解)
- 将A的所有前缀在B中匹配,prei为A[1到i]可以匹配到的最大的B的前缀
则prei=prei-1 + (Ai == Bpre[i-1]+1) - 将A的所有后缀在B中匹配,sufi为A[i到n]可以匹配到的最大的B的后缀
则sufi=sufi+1 + (Ai == Bsuf[i+1]-1) - 答案为min 1 <= i <= n {sufi+1 - prei - 1}
时间复杂度:O(n)
空间复杂度:O(n)
代码实现(正解)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int P = 1e9 + 7;
const int N = 10000005;
char a[N], b[N];
ll c[N];
int pre[N], suf[N];
int n, m;
int main() {
int t;
cin >> t;
if (t == 0) {
cin >> a + 1 >> b + 1;
} else {
// 构造字符串
int x, y;
cin >> c[1] >> x >> y >> n;
a[1] = 'a' + c[1] % 26;
for (int i = 2; i <= n; ++i) {
c[i] = (c[i - 1] * x + y) % P;
a[i] = 'a' + c[i] % 26;
}
cin >> c[1] >> x >> y >> m;
b[1] = 'a' + c[1] % 26;
for (int i = 2; i <= m; ++i) {
c[i] = (c[i - 1] * x + y) % P;
b[i] = 'a' + c[i] % 26;
}
}
n = strlen(a + 1);
m = strlen(b + 1);
for (int i = 1; i <= n; ++i) {
pre[i] = pre[i - 1];
if (pre[i] < m && a[i] == b[pre[i] + 1]) {
++pre[i];
}
}
suf[n + 1] = m + 1;
for (int i = n; i >= 1; i--) {
suf[i] = suf[i + 1];
if (suf[i] > 1 && a[i] == b[suf[i] - 1]) {
--suf[i];
}
}
int res = m;
for (int i = 0; i <= n; ++i) {
res = min(res, suf[i + 1] - pre[i] - 1);
}
cout << max(res, 0) << '\n';
return 0;
}