蓝桥杯 契合匹配

原题目链接

题目描述

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

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

例如:

  • "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的子串。

相关推荐
β添砖java7 小时前
深度优先搜索DFS
算法·深度优先
小糯米6017 小时前
C++ 并查集
java·c++·算法
IronMurphy7 小时前
【算法三十四】39. 组合总和
算法·深度优先
重庆小透明7 小时前
力扣刷题【3】相交链表
算法·leetcode·链表
算法鑫探7 小时前
C语言实战:学生成绩统计与分析
c语言·数据结构·算法·新人首发
IAUTOMOBILE7 小时前
Code Marathon 项目源码解析与技术实践
java·前端·算法
Lyyaoo.7 小时前
【JAVA基础面经】深拷贝与浅拷贝
java·开发语言·算法
x_xbx8 小时前
LeetCode:202. 快乐数
算法·leetcode·职场和发展
老虎06278 小时前
LeetCode热题100 刷题笔记(第四天)二分 「 寻找两个正序数组的中位数」
笔记·算法·leetcode
_日拱一卒8 小时前
LeetCode:最小覆盖字串
java·数据结构·算法·leetcode·职场和发展