POJ 1590 -- 回文词

博客详细介绍了如何解决POJ 1590问题,涉及判断字符串是否为回文串或镜像串。作者分享了自己的思路,包括使用双指针判断回文和建立字符数组检查镜像串,同时也提到书中更优的解决方案,如使用const常量数组,巧妙的输出格式处理,以及ctype.h库中的函数应用。
摘要由CSDN通过智能技术生成

一、题目

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]就表示了头尾对称的两个字符,哪儿像我傻不拉几还去定义两个指针。

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值