题意:
给两个字符串 A , B ,长度 A > B,B 是 A 的子串,问最多删除多少个字符 B 依然是 A 的子串(子串定义不同,本题子串指的是例如 test 的子串有 test , tes , tet , est ,tst, te, ts ,tt ,es ,st, et, t ,e ,s ,t,即可以不连续)
思路:
首先暴力的思路肯定是有的,但是只能过D1,不适合D2,所以只能另想思路
首先我们可以确定一点,对于一个子串,如果让它的开始和结束位置尽可能居中,就可以保证两端留出来的可以删除的区域最大,因此可以正向扫一遍,遇到对应的子串就记录位置,最后的一个字符的位置就是右边的最居中位置,然后反向扫一遍可以得到开头字符的最居中位置,可以由此得到一个可删除的最大长度。
其次,还有可能删除中间的字符能得到最大值,例如 affbcdef 和 abcde 这显然就是删除 a 和 b 中间的两个f才能得到最大结果,因此还需要考虑中间删除,但是是否相邻的两个值删除就是正确结果呢?
显然不是,对于另一个例子,affaffffbcdef 和 abcde 删除两端和显然得不到最大值,删除相邻字符的间距只能得到4个 f ,但是显然应该是删除开头 a 和 b 中间所有的,对于这样的情况,显然是让相邻的两个字符间距尽可能大,最大情况其实就是最右边的后一个字符和最前面的当前字符的间距,也就是反向遍历得到的下一个字符的位置和正向遍历得到的当前字符的位置的差值。
可以结合下面的图理解一下
#include <cstdio>
#include <iostream>
#define endl "\n"
#include <cstring>
using namespace std;
string a, b;
const int maxn = 1e5 + 10;
int L[maxn * 2], R[maxn * 2];
int main()
{
#ifdef endl
cin.tie(0);
cout.tie(0);
ios::sync_with_stdio(0);
#endif
cin >> a >> b;
int lena = a.length();
int lenb = b.length();
int j, i, res;
j = 0;
int l, r;
res = -1;
for (i = 0; i < lenb; i++){
while (a[j] != b[i]){
++j;
}
L[i] = j;//正向遍历求最靠前的位置
++j;
}
r = j - 1;
j = lena - 1;
for (i = lenb - 1; i >= 0; i--){
while (a[j] != b[i])--j;
R[i] = j;//反向遍历求最靠后的位置
--j;
}
l = j + 1;
res = max(l, lena - r - 1);//两个端点的情况
for (int i = 0; i < lenb - 1; i++)res = max(res, R[i + 1] - L[i] - 1);
cout << res << endl;
return 0;
}