蓝桥杯 契合匹配

原题目链接

题目描述

小蓝有很多齿轮,每个齿轮的凸起和凹陷分别用一个字符表示,一个字符串表示一个齿轮。

如果两个齿轮的对应位分别是同一个字母的大小写,我们称这两个齿轮是契合的。

例如:

  • "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 中的小写字母相对应。例如,aBcdEfAbCDeF 是契合的。

为了简化判断过程,我们可以将字符串 b 中的大写字母全部转换为小写字母,小写字母转换为大写字母。假设字符串 bAbCDeF,经过转换后变为 aBcdEf。此时,问题就转化为判断字符串 a 和转换后的字符串 b 是否相等。

通过这种方法,我们可以轻松判断两个字符串是否相契合。

当然这是不考虑旋转的情况,要考虑旋转,我们就要用到破环成链思想。

如果一个字符串 S (abcdef )扩展成两倍 S′ ( abcdefabcdef ),那么从 S′ 的第二个字符开始 6 个字符组成的子串( bcdefa ),实际上就是 S 逆时针旋转 1 位的字符串,同时也是顺时针旋转 5 位的情况。

那么这个问题就转换为了,T转换过后的字符串是否是两倍S的子串。

相关推荐
进击的小头2 小时前
第5篇:最优控制问题的组成
python·算法
轻颂呀2 小时前
排序——堆排序
数据结构·算法
WolfGang0073212 小时前
代码随想录算法训练营 Day07 | 字符串 part01
数据结构·算法·leetcode
luckycoding2 小时前
488. 祖玛游戏
算法·游戏·深度优先
8Qi82 小时前
LeetCode61. 旋转链表
c语言·数据结构·c++·算法·leetcode·链表·力扣
眼眸流转2 小时前
LeetCode热题100(一)
算法·leetcode
渡过晚枫2 小时前
[第十六届蓝桥杯/java/算法]1.偏蓝
java·算法·蓝桥杯
2501_940315262 小时前
【无标题】1302 层数最深叶子节点的和
java·数据结构·算法
invincible_Tang2 小时前
AcWing 796. 子矩阵的和 _
数据结构·算法