题目描述
小蓝有很多齿轮,每个齿轮的凸起和凹陷分别用一个字符表示,一个字符串表示一个齿轮。
如果两个齿轮的对应位分别是同一个字母的大小写,我们称这两个齿轮是契合的。
例如:
- "AbCDeFgh" 和 "aBcdEfGH" 是契合的
- "abc" 和 "aBC" 不是契合的
这天,小蓝的弟弟小桥从抽屉里拿来了两个齿轮,小蓝想知道,这两个齿轮是不是契合的。
特别需要注意的是,齿轮是环形的,所以是可以旋转的(顺时针和逆时针均可)。如果是契合的,小蓝还想让你告诉他,最少将第一个齿轮旋转多少位,两个齿轮可以完全契合在一起。
例如:
- "AbbCd" 和 "BcDaB" ,将第一个齿轮逆时针旋转两位后变成 "bCdAb",两个齿轮就完全契合在一起了。
输入格式:
- 第一行输入一个正整数
n,表示两个齿轮的长度。 - 第二行输入一个长度为
n的字符串S,表示第一个齿轮。 - 第三行输入一个长度为
n的字符串T,表示第二个齿轮。
输出格式:
- 第一行输出一个字符串:"Yes" 或者 "No",表示两个齿轮是否契合。
- 如果可以契合,第二行输出一个整数,表示需要旋转的位数。
- 如果不可以契合,不用多余输出。
样例输入:
in
5
AbbCd
BcDaB
样例输出:
out
Yes
2
评测数据范围:
- 1 ≤ n ≤ 10^6
- 保证字符串只包含大小写字母。
c++代码(超时版)
cpp
#include<bits/stdc++.h>
using namespace std;
int n;
string S, T;
int main() {
cin >> n >> S >> T;
for (int i = 0; i < n; i++) {
if (isupper(T[i])) T[i] = tolower(T[i]);
else T[i] = toupper(T[i]);
}
S += S;
int k = S.find(T);
k = min(k, n - k);
if (k == -1) cout << "No" << endl;
else cout << "Yes" << endl << k << endl;
return 0;
}//by wqs
c++代码(KMP算法优化)
cpp
#include<bits/stdc++.h>
using namespace std;
int n;
string S, T;
int Next[1000009];
void getNext(string p) {
Next[0] = 0, Next[1] = 0;
for (int i = 1; i < p.size(); i++) {
int j = Next[i];
while (j && p[i] != p[j]) j = Next[j];
if (p[i] == p[j]) Next[i + 1] = j + 1;
else Next[i + 1] = 0;
}
}
int kmp(string s, string p) {
getNext(p);
int j = 0;
for (int i = 0; i < s.size(); i++) {
while (j && s[i] != p[j]) j = Next[j];
if (s[i] == p[j]) j++;
if (j == p.size()) return i + 1 - p.size();
}
return -1;
}
int main() {
cin >> n >> S >> T;
for (int i = 0; i < n; i++) {
if (isupper(T[i])) T[i] = tolower(T[i]);
else T[i] = toupper(T[i]);
}
S += S;
int k = kmp(S, T);
k = min(k, n - k);
if (k == -1) cout << "No" << endl;
else cout << "Yes" << endl << k << endl;
return 0;
}//by wqs
我们首先不考虑旋转 ,判断字符串 a 和字符串 b 是否契合,等价于:a 中的小写字母与 b 中的大写字母相对应,a 中的大写字母与 b 中的小写字母相对应。例如,aBcdEf 和 AbCDeF 是契合的。
为了简化判断过程,我们可以将字符串 b 中的大写字母全部转换为小写字母,小写字母转换为大写字母。假设字符串 b 为 AbCDeF,经过转换后变为 aBcdEf。此时,问题就转化为判断字符串 a 和转换后的字符串 b 是否相等。
通过这种方法,我们可以轻松判断两个字符串是否相契合。
当然这是不考虑旋转的情况,要考虑旋转,我们就要用到破环成链思想。
如果一个字符串 S (abcdef )扩展成两倍 S′ ( abcdefabcdef ),那么从 S′ 的第二个字符开始 6 个字符组成的子串( bcdefa ),实际上就是 S 逆时针旋转 1 位的字符串,同时也是顺时针旋转 5 位的情况。
那么这个问题就转换为了,T转换过后的字符串是否是两倍S的子串。