【USACO1.3.3】回文串

本文介绍了一种在给定字符串中寻找最长回文串的方法,包括处理字符串、判断回文串的具体实现步骤,并分享了作者的编程经验和技巧。

题目

【问题描述】

 据说如果你给无限只母牛和无限台巨型便携式电脑(有非常大的键盘),那么母牛们会制造出世上最棒的回文。你的工作就是去寻找这些牛制造的奇观(最棒的回文)。

 在寻找回文时不用理睬那些标点符号、空格(但应该保留下来以便做为答案输出),只用考虑字母’A’-‘Z’和’a’-‘z’。要你寻找的最长的回文的文章是一个不超过20,000个字符的字符串。

 我们将保证最长的回文不会超过2,000个字符(在除去标点符号、空格之前)。

【输入格式】  

输入文件不会超过20,000字符。这个文件可能一行或多行,但是每行都不超过80个字符(不包括最后的换行符)。

【输出格式】  

输出的第一行应该包括找到的最长的回文的长度。
下一行或几行应该包括这个回文的原文(没有除去标点符号、空格),把这个回文输出到一行或多行(如果回文中包括换行符)。
如果有多个回文长度都等于最大值,输出最前面出现的那一个。

【输入样例】  

Confucius say: Madam, I’m Adam.

【输出样例】  

11
Madam, I’m Adam

分析

我们来想想回文串的判断方法,要么是直接判断,要么是dp,dp的话每种情况都会考虑到咋一想挺好的还特别好写,但是一算时间复杂度n*n是过不了的,而且剪枝很麻烦哎基本上剪不了
那我们就直接判断,这种方法时间复杂度也是n*n,但实际上中图有很多直接退出了,如果加上一个预测剪枝那绝对就是过了(我没加哈哈哈)
对于这种数据繁杂的题目,应该想到的是标准化,再想办法还原
还有一个就是答案的记录问题,之前有想过记录中间数,记录长度,直接记录数据什么的,但实际上只记录左端点是第几个字母+长度即可

代码

#include<queue>
#include<cmath>
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define LOCAL
const int maxn=20005; 
char s[maxn],a[maxn];
int n,m,chang,f;
void Init()
{
    char c;
    while( ( c = getchar() ) != EOF )
    {
        s[n++]=c;
        c=tolower(c);
        if(isalpha(c))
            a[m++]=c;
    }
    s[n]='\0';
    a[m]='\0';
}
void solve()
{
    for(int i=0;i<m;i++)//奇数 
    {
        int l,r;
        for(l=i,r=i;l>=0&&r<m;l--,r++)
        {
            if(a[l]==a[r])
            {
                if(r-l+1>chang)
                {
                    chang=r-l+1;
                    f=l+1;
                }
            }
            else
                break;
        }
    }
    for(int i=0;i<m;i++)//偶数 
    {
        int l,r;
        for(l=i,r=i+1;l>=0&&r<=m;l--,r++)
        {
            if(a[l]==a[r])
            {
                if(r-l+1>chang)
                {
                    chang=r-l+1;
                    f=l+1;
                }
            }
            else
                break;
        }
    }
}
void outs()
{
    cout<<chang<<endl;
    int cnt=0;
    for(int i=0;i<n;i++)
    {
        if(isalpha(s[i]))
            cnt++;
        if(cnt==f)
        {
            int t=0;
            for(int j=0;t<chang;j++)
            {
                putchar(s[i+j]);
                if(isalpha(s[i+j]))
                {
                    t++;
                }
            }
            break;
        }
    }
}
int main()
{
    //freopen("in.txt","r",stdin);
    Init();
    solve();
    outs();
    return 0;
}

细节

1、字符串处理问题
a、末尾0的位置下标=字符串长度
b、手动读入字符串的时候,用n++,然后最后在n的位置补上0,则刚刚好
c、是’\0’不是’/0’
d、记得从0开始处理
(代码的很多函数应该是cctype里面的,我故意去掉之后还是通过了,当然多写点头文件没什么毛病)

关于逗号

逗号的含义:一个优先级很低的位运算符。
从左到右一次执行语句并且返回最后一个语句的值,千万不要误以为和&&相同,for循环里面的中间那一重就不要用。
逗号是一个语句,意味着可以在if或者循环下面减少括号,当然必须有返回值的语句才能这么用,continue这些就不行

收获

1、回文串判断
a、直接搜索
b、dp
2、字符串的处理
3、关于逗号

再说一句

这道题我很早就尝试做过了,当时的思路很好,但是因为代码能力确实没有实现出来,如今再来做倒是畅快了不少,也没有想象的难,但是还是有很多技巧的

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值