UVa401 - Palindromes 题解

题目

题目地址

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种状态。

posted @ 2020-10-27 22:18  1v7w  阅读(148)  评论(0编辑  收藏  举报