题目链接:https://www.luogu.com.cn/problem/UVA401
回文串的判断不难,难点在于镜像串的判断,所谓镜像串
就是根据题目的镜像表两次镜像后保持原样就是镜像串,第一次镜像后得到的是这个串的倒像,所以判断一个镜像串的依据就是一次翻转后是这个串的倒像。
问题在于怎么镜像,写个函数整个串镜像?还是写个函数只镜像单个字符?显然如果我们镜像整个串会麻烦很多,所以选择镜像单个字符。随之而来的问题是我们怎么存题目给的镜像表,我一开始的想法是用两个string分别存原字符和镜像字符,然后每次镜像时先找到该字符位置,然后找这个位置对应的镜像字符。后来看到题解就惊了,怎么就这么点代码。
看完才明白自己想复杂了,这个镜像表是有规律的,从A ~ Z
26个字母 + 1 ~ 9
( 9个数字),但凡是有规律的东西都能够做简化,我之前想要用两个string,但存原字符的那个string可以省略,然后我们也不需要查找字符再找镜像,因为镜像表是有规律的。具体做法看代码理解。
#include <bits/stdc++.h>
using namespace std;
string s = "A 3 HIL JM O 2TUVWXY51SE Z 8 ";
string res[] = { "is not a palindrome.","is a regular palindrome.","is a mirrored string.","is a mirrored palindrome." };
int mir(char a) {
if (isalpha(a))return s[a - 'A'];//字母
return s[a - '0' + 25];//数字
}
int main()
{
#ifdef LOCAL
freopen("1.txt", "r", stdin);
#endif // LOCAL
string a;
int t1, t2;//分别用来判断是否为回文串和镜像串
while (cin >> a) {
t1 = t2 = 1;
int len = a.length();
for (int i = 0; i < len; i++) {
if (a[i] != a[len - i - 1])t1 = 0;
//如果a[i]的镜像字符不等于a[len-i-1],t2=0
if (mir(a[i]) != a[len - i - 1])t2 = 0;
}
cout << a << " -- " << res[t1 + 2 * t2] << endl;
cout << endl;
}
return 0;
}
这是根据书上的例子稍作修改的代码,我觉得很巧妙的一个地方在最后输出的结果上,如果是一般人,都会在最后写上4个if判断,不同情况输出,而书的作者直接先把四个结果存起来,我们知道两位二进制可以得到4种不同的结果0,1,2,3,正好我们的输出结果也就是四种,所以就将t1,t2作为二进制位得到一个数t1+2t2(这里也可以t2+2t1,但res数组存的字符串顺序也要随之改变),用这个数作为下标来访问存放结果的数组,输出字符串。
这个方法保证了每组t1,t2都有一个唯一对应的结果t1+2*t2,而且不同的t1,t2一定有不同的输出结果。
只用少量的代码就能解决一个看似复杂的问题,这就是大犇吧。