题目: 传送门
思路:
我们从逆向的思维考虑,即每次将 T串的头部或尾部放到任意位置,使其成为 S串. 那么从贪心的角度想我们肯定希望每个数最多只进行一次交换,最终就能符合结果. 很明显 如果我们可以把T串分为三部分, 分别为 需要移动的部分,不需要移动的部分,需要移动的部分,不需要移动的部分肯定是 S串的子序列,这样他才能满足不需要移动就可以让最终结果满足.对于需要移动的部分,每次就只需要一步操作即能放到满足的位置.那么结果就是需要移动部分的长度。
我们直接枚举不需要移动的部分的开头,每次用 26 个指针 扫一遍求得最长的子序列,然后去min即可.
记得特判不可能的情况
Ac_Code
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <stack>
#include <bitset>
#include <vector>
#include <map>
#include <string>
#include <cstring>
#define fir first
#define sec second
using namespace std;
int n;
int h[30],p[30][110],lst[30];
int sz[30];
char s[110];
char t[110];
int main() {
int q;
scanf("%d",&q);
while(q--) {
memset(p,0,sizeof(p));
memset(lst,0,sizeof(lst));
memset(sz,0,sizeof(sz));
scanf("%d",&n);
scanf("%s%s",s,t);
for(int i=0;i<n;i++) {
int c = s[i] - 'a';
p[c][lst[c]++] = i;
}
for(int i=0;i<n;i++) {
sz[t[i]-'a']++;
}
int flag = 1;
for(int i=0;i<26;i++) {
if(sz[i] != lst[i]) flag = 0;
}
if(!flag) printf("-1\n");
else {
int ans = 500;
for(int i=0;i<n;i++) {
int now = i;
int R= -1;
memset(h,0,sizeof(h));
while(true) {
int c = t[now] -'a';
while(h[c] < lst[c] && p[c][h[c]] <= R) h[c]++;
if(h[c] >= lst[c]) break;
R = p[c][h[c]];
now++;
if(now == n) break;
}
ans = min(ans,n-now+i);
// printf("%d %d\n", now,R);
}
printf("%d\n", ans);
}
}
return 0;
}