UVa401 - Palindromes 题解
题目
题目地址
题目大意
输入一个字符串,判断它是否为回文串以及镜像串。输入字符保证不含数字0。所谓回文串,就是反转以后和原串相同,如abba和madam。所谓镜像串,就是左右镜像之后和原串相同,如2S和3AIAE。注意,并不是每个字符在镜像之后都能得到一个合法字符。在本体中,每个字符的镜像如图所示(空白项表示该字符镜像后不能得到一个合法字符)。
样例输入
NOTAPALINDROME
ISAPALINILAPASI
2A3MEAS
ATOYOTA
样例输出
NOTAPALINDROME -- is not a palindrome.
ISAPALINILAPASI -- is a regular palindrome.
2A3MEAS -- is a mirrored string.
ATOYOTA -- is a mirrored palindrome.
注意
每行输出后要有一个空行。
题解
我的思路
我想着先把字符串给读入进来,然后分别处理回文与镜像。
假设读入字符串a,a的长度为len
回文处理就很简单,只需要判断a[i] == a[len-i-1],i从0到len-1。
镜像处理我想着先判断字符串a里是不是有非法字符(镜像后的字符为空),如果有非法字符,那肯定不是镜像串。如果没有非法字符,那就将字符串a镜像后的字符串b保存起来,然后来判断a[i] == b[i]。
很简单的思路。
不过我TM查错了n遍才AC是因为我没有每行输出后再输出一个空行。。。
Then show code.
#include <stdio.h>
#include <string.h>
int main(){
char mir[2][25] = {0}, outMir[25] = {0};
int lenMir;
// int kase = 0;
strcpy(mir[0], "AEHIJLMOSTUVWXYZ12358");
strcpy(mir[1], "A3HILJMO2TUVWXY51SEZ8");
strcpy(outMir, "BCDFGKNPQR4679");
lenMir = strlen(mir[0]);
char a[1000], b[1000];
while(scanf("%s", a) == 1){
memset(b, 0, sizeof(b));
//flag1为回文串 flag2为镜像串
int flag1, flag2;
flag1 = flag2 = 1;
int len = strlen(a);
//判断是否为回文串
for(int i = 0; i < len; i++){
if(a[i] != a[len-i-1]){
flag1 = 0;
break;
}
}
//判断是否有不是镜像字符的
for(int i = 0; i < len; i++){
if(strstr(outMir, &a[i]) != NULL){
flag2 = 0;
break;
}
}
//处理镜像串 将a的镜像串保存到b中
if(flag2){
for(int i = 0; i < len; i++){
for(int j = 0; j < lenMir; j++){
if(mir[0][j] == a[i]){
b[len-i-1] = mir[1][j];
break;
}else if(mir[1][j] == a[i]){
b[len-i-1] = mir[0][j];
break;
}
}
}
//判断字符串是否为镜像串
for(int i = 0; i < len; i++){
if(a[i] != b[i]){
flag2 = 0;
break;
}
}
}
// if(kase++)
// printf("\n\n");
if(flag1 && flag2)
printf("%s -- is a mirrored palindrome.", a);
else if(flag1 && !flag2)
printf("%s -- is a regular palindrome.", a);
else if(!flag1 && flag2)
printf("%s -- is a mirrored string.", a);
else if(!flag1 && !flag2)
printf("%s -- is not a palindrome.", a);
printf("\n\n");
}
return 0;
}
刘汝佳的思路
这道题是《算法竞赛入门经典(第二版)》上的例题,他有提供了一个很简短的解法,非常的amazing啊。
来看一下代码。
#include <stdio.h>
#include <ctype.h>
#include <string.h>
const char *rev = "A 3 HIL JM O 2TUVWXY51SE Z 8 ";
const char *msg[] = {"is not a palindrome", "is a regular palindrome", "is a mirrored string", "is a mirrored palindrome"};
char getRev(char ch){
if(isalpha(ch)) return rev[ch-'A'];
else return rev[ch-'0'+25];
}
int main(){
char a[30];
while(scanf("%s", a) == 1){
int p, m, len;
p = m = 1;
len = strlen(a);
for(int i = 0; i < (len+1)/2; i++){
if(a[i] != a[len-i-1]) p = 0;
if(getRev(a[i]) != a[len-i-1]) m = 0;
}
printf("%s -- %s.\n\n", a, msg[m*2+p]);
}
return 0;
}
可以看到代码非常的简短啊。
他整体思路是遍历字符串a的每个字符,然后同时判断是否满足回文与镜像。
他自定义了一个函数用来返回镜像反转后的字符。这个自定义函数里用到了isalpha(),这个函数是判断是否为字母,包含在ctype.h头文件里。
这里面的punchline(特别妙的点)就是他定义了个常量数组rev来存放镜像后的字符,多的我也不说,细细品吧。
msg数组的用法也很妙,其实就是2位二进制能表示4种状态。
不忘初心方得始终