POJ 1590 -- 回文词

来源:互联网 发布:php获取url参数 编辑:程序博客网 时间:2024/05/16 12:16

一、题目

1590题,要求判断一个字符串是否是回文串或镜像串。回文串,就是将字符串倒序排列,与原串相同,如abba和madam;镜像串,先将串中每个字符做镜像,然后将字符串倒序排列后,与原串相同,如2S(2的镜像是S,S的镜像是2),以及3AIAE(3、E互为镜像)。并非每个字符镜像后都是合法字符,如下图,空白代表非法字符。

图1 镜像字符

题目要求:输入每行包含一个字符串(保证只有上图中Character列的字符,即大写字母与数字),判断它是否为回文串或镜像串(共4种组合),每组数据后输出一个空行。

样例输入:
NOTAPALINDROME
ISAPALINILAPASI
2A3MEAS
ATOYOTA

样例输出:
NOTAPALINDROME – is not a palindrome.

ISAPALINILAPASI – is a regular palindrome.

2A3MEAS – is a mirrored string.

ATOYOTA – is a mirrored palindrome.

二、我的思路

我的思路非常stupid:

  1. 判断回文:使用两个指针分别指向输入字符串的第一个和最后一个字符,比较指针内容,若相同,则同时向中间移一格,继续比较,如此比了移,移了比,直到两个指针内容不等(不是回文),或头指针已经在尾指针右边了(是回文),结束。

  2. 判断镜像:用一个含21个元素的全局字符数组,将上图中拥有合法镜像字符的21个字符置于数组中,扫描一遍字符串,查看是否包含非法镜像字符,若有,则不是镜像,若无,则是。(注意,我忽略了镜像串也需要倒序相等的特点)

于是,写成代码如下:

#include <stdio.h>char mirror[21] = {'A','E','H','I','L','J','M','O','S','T','U','V','W','X','Y','Z','1','2','3','5','8'};bool isMirror(char c){    for(int i=0; i<21; i++){        if(c==mirror[i])            return true;    }    return false;}int main(){    char input[200];    while(scanf("%s", input) == 1){        char* head = input;        char* tail = input;        int len    = 0;        while(*tail != '\0'){            tail++;            len++;        }        tail = tail - 1;        bool is_par = true;        bool is_mir = true;        //if the string is a palindrom or a mirror string        for(int i=0; i<len; i++){            if(i<(len/2) && *head != *tail)                is_par = false;            if(!isMirror(*head))                is_mir = false;            head++;            tail--;        }        //output        if(is_par && is_mir)            printf("%s -- is a mirrored palindrome.\n\n", input);        else if(is_par && !is_mir)            printf("%s -- is a regular palindrome.\n\n", input);        else if(!is_par && is_mir)            printf("%s -- is a mirrored string.\n\n", input);        else            printf("%s -- is not a palindrome.\n\n", input);    }    return 0;}

注意,在我没有实现镜像串的倒序相等特点的情况下,提交至POJ,通过。估计它只看题目中给的4个样例的结果,完全符合就行了。

顺便提一嘴,刷题中,输出的格式异常重要,一个字符都不能错,比如这里最后的“.”,以及输出一行字符以后还得空一行等。所以,当它报出“Wrong Answer”的错误时,首先检查是否输出格式有问题。

三、书上思路

刘汝佳的《算法竞赛入门经典》,由于我没搞过ACM,真是相见恨晚,里面专业而细致的描述、简短而有力的代码,让初爱编程者爱不释手。

来看书中49页对此题的解法:

#include <stdio.h>#include <string.h>#include <ctype.h>const char* mir = "A   3  HIL JM O   2TUVWXY51SE Z  8 ";const char* msg[] = {"not a palindrome.", "a regular palindrome.",                         "a mirrored string.", "a mirrored palindrome."};char mirrored(char c){    if(isalpha(c))        return mir[c - 'A'];    return mir[c - '0' + 25];}int main(){    char s[200];    while(scanf("%s", s)==1){        int len = strlen(s);        int p = 1, m = 1;        for(int i=0; i<(len+1)/2; i++){            if(s[i] != s[len-i-1])                p = 0;// is not a palindrome            if(mirrored(s[i]) != s[len-1-i])                m = 0;//is not a mirrored string        }        printf("%s -- is %s\n\n", s, msg[2*m+p]);    }    return 0;}

对于编程渣的我来说,其中的亮点有:

  1. 开头定义了两个常量数组,注意,尽量用const来声明常数(《算法竞赛入门经典》P6 提示1-7);
  2. 常量字符串数组msg[],以及遥相辉映地最后printf那句代码,简直不能再机智,所以在程序中用int而非bool来表示“是”“否”;
  3. 使用isalpha()函数来判断字符是否为英文字母,类似地还有idigit(十进制数字)、isprint(可打印字符,其ASCII码值大于 0x1f(除0x7f(DEL)外))、toupper和tolower则用来转换字母大小写,这些都定义在ctype.h中;
  4. mirrored函数中的两个return,是熟练运用ASCII码计算的表现,多么简洁有力;
  5. 将scanf()放在while的条件中,既能输入,又能循环,一举两得;
  6. for循环中,就用s[i]、s[len-1-i]就表示了头尾对称的两个字符,哪儿像我傻不拉几还去定义两个指针。

哈哈,看高手代码就是开心!

0 0
原创粉丝点击