ZOJ-2744-Palindromes
2006-05-16 07:29
246 查看
这道题唤起了我遥远的记忆,Palindromes-回文。
我高2时,参加省信息学奥赛复赛时,就遇见了这道题,具体细节是否一样根本记不清了,但是回文我绝对忘不了,那时我觉得这题很简单,便直接开始做,没想到一直到所有时间用完,都没出结果,于是连之后的评审都没参加,黯然离开考场。那之后,我就不太接触信息学奥赛了。其实后来也知道了,当时的算法基本是正确的,可惜因为我放弃bascal,执意用的刚学会的pascal参赛,语法不熟练,导致表达式写错,但这些也许都不能成为理由吧。
觉得可惜的是,当时我虽然已经进了复赛,可我对这个东西完全没有一点了解,认为只是编编算东西的小程序而已,不像今天,互联网上可以很快搜索出很多相关信息。我那时不知道什么是算法数据结构,连使用pascal也只不过因为参赛前的暑假上的课里用的是这个语言。不过今天看来,pascal语言严谨的语法与表达,还是对我产生了很深的影响。
话说回来,事情已经过去了,虽然有点遗憾,比如当时如果能够更深地了解一下有关比赛的背景什么的,不过人生来不得半点假如,尽管遗憾,也参杂着回忆的甘甜,我喜欢我现在的状态,我也会在现在这个起跑线上继续努力。
回到题目本身。题目是要求对于一个输入的字符串,统计它所有可以成为回文的子串的数目,从单个的字母到输入的字符串本身都算子串,限时1秒,就不贴题目了。字符串是从str[0]到str[n-1]一共有n个字符。
1.拿到题目,首先想到的就是,我可以按子串长度展开搜索
首先初试化sum=0
sum+=n,加上长度为1的子串数目
接着是长度为2,3,直到n-1,子串长度和这个长度的子串的总数也很容易求出。对于一个长度大于1的子串,从它的两头开始对比,一旦发现不相等(说明不是回文)就停下,继续对比下一个子串。如果全部相等,就sum++
得解。
虽然从结果和过程来看,应该是正确的,可是用时过多,提交以后TLE。只能重新想办法。
2.于是我重新构思,从增加代码的重复可用性角度入手,增加了一个子函数,重新写了程序
可以看到,下面这段代码虽然同样实现的是第一种算法,但却有种简约的美,没有多余的枝节判断与处理,将step>=2的情况进行了统一的处理,所以这段代码比上面的要漂亮很多。
可惜因为复杂度和第一种方法相差无几,所以依然TLE
3.为了AC,我重新构思算法,完全抛开之前的算法,这次我成功的减少了一个层循环。
外层循环从1,到n-2,对于中间每一个str[]调用两次子函数check:
checkstr(i,i);
checkstr(i-1,i);
check函数以两个入口变量是否相等,做不同处理。相等时,以输入的字符位置i为中心从内向外检查长度为奇数的子串;不相等时,对以i-1,i为中心的长度为偶数的字符串进行检查。
从内向往检查的原则是,一旦两个字符相等,便sum++,然后两头的指针各向外移动一步,再检查,直到不相等,便说明不能再有回文字符串了,便停止,或者两头指针超过了[0,n-1]的范围时,也停止。然后中心移到下一个字符。对每个字符都进行奇中心和偶中心两遍搜索。
终于AC,time=0.09s,memory=388k。可见算法的改进对于程序来说,的确是数量级的改进,很多时候甚至能比硬件的改进发挥更大的作用!这道题加深了我对算法重要性的认识。
输出输入改为c的格式是为了不#include<iostream>,可以节省一点内存,这样在用时相同的情况下,内存用的少的排名比较靠前嘻嘻
END:但是说回来,到现在为止,最快的家伙用时是0.03秒,说明对于我上面的程序,依然有很大的改进的余地,我想思路应该从统一奇偶两种搜索入手,减少对子函数的调用次数,得到更简洁的方法呵呵,有空再改。
我高2时,参加省信息学奥赛复赛时,就遇见了这道题,具体细节是否一样根本记不清了,但是回文我绝对忘不了,那时我觉得这题很简单,便直接开始做,没想到一直到所有时间用完,都没出结果,于是连之后的评审都没参加,黯然离开考场。那之后,我就不太接触信息学奥赛了。其实后来也知道了,当时的算法基本是正确的,可惜因为我放弃bascal,执意用的刚学会的pascal参赛,语法不熟练,导致表达式写错,但这些也许都不能成为理由吧。
觉得可惜的是,当时我虽然已经进了复赛,可我对这个东西完全没有一点了解,认为只是编编算东西的小程序而已,不像今天,互联网上可以很快搜索出很多相关信息。我那时不知道什么是算法数据结构,连使用pascal也只不过因为参赛前的暑假上的课里用的是这个语言。不过今天看来,pascal语言严谨的语法与表达,还是对我产生了很深的影响。
话说回来,事情已经过去了,虽然有点遗憾,比如当时如果能够更深地了解一下有关比赛的背景什么的,不过人生来不得半点假如,尽管遗憾,也参杂着回忆的甘甜,我喜欢我现在的状态,我也会在现在这个起跑线上继续努力。
回到题目本身。题目是要求对于一个输入的字符串,统计它所有可以成为回文的子串的数目,从单个的字母到输入的字符串本身都算子串,限时1秒,就不贴题目了。字符串是从str[0]到str[n-1]一共有n个字符。
1.拿到题目,首先想到的就是,我可以按子串长度展开搜索
首先初试化sum=0
sum+=n,加上长度为1的子串数目
接着是长度为2,3,直到n-1,子串长度和这个长度的子串的总数也很容易求出。对于一个长度大于1的子串,从它的两头开始对比,一旦发现不相等(说明不是回文)就停下,继续对比下一个子串。如果全部相等,就sum++
得解。
虽然从结果和过程来看,应该是正确的,可是用时过多,提交以后TLE。只能重新想办法。
1.按子串长度展开搜索.TLE,time>1s |
#include <iostream> using namespace std; char str[5001]; int n,sum; int main() { int i,key,flag,step,hp,ep; while(cin>>str) { sum=0;flag=1; n=strlen(str); sum+=n; if(n>=2) { for(i=0;i<n-1;i++) { if(str[i]==str[i+1]) sum++; } } if(n>2) { for(step=3;step<=n;step++) { if((step%2)==1) key=step-1; else key=step; for(i=0;i<=n-step;i++) { flag=1; hp=i;ep=i+step-1; while(ep>hp) { if(str[hp++]!=str[ep--]) { flag=0;break; } } if(flag) { sum++; } } } } cout<<sum<<endl; } return 0; } |
可以看到,下面这段代码虽然同样实现的是第一种算法,但却有种简约的美,没有多余的枝节判断与处理,将step>=2的情况进行了统一的处理,所以这段代码比上面的要漂亮很多。
可惜因为复杂度和第一种方法相差无几,所以依然TLE
2.按子串长度展开搜索的改进.TLE,time>1s |
#include <iostream> using namespace std; char str[5001]; int n,sum; bool check(int hp,int ep) { while(ep>hp) { if(str[hp++]!=str[ep--]) { return false; } } return true; } int main() { int i,j,key; while(cin>>str) { sum=0; n=strlen(str); sum+=n; for(i=0;i<n-1;i++) { for(j=i+1;j<n;j++) { if(check(i,j)) sum++; } } cout<<sum<<endl; } return 0; } |
外层循环从1,到n-2,对于中间每一个str[]调用两次子函数check:
checkstr(i,i);
checkstr(i-1,i);
check函数以两个入口变量是否相等,做不同处理。相等时,以输入的字符位置i为中心从内向外检查长度为奇数的子串;不相等时,对以i-1,i为中心的长度为偶数的字符串进行检查。
从内向往检查的原则是,一旦两个字符相等,便sum++,然后两头的指针各向外移动一步,再检查,直到不相等,便说明不能再有回文字符串了,便停止,或者两头指针超过了[0,n-1]的范围时,也停止。然后中心移到下一个字符。对每个字符都进行奇中心和偶中心两遍搜索。
终于AC,time=0.09s,memory=388k。可见算法的改进对于程序来说,的确是数量级的改进,很多时候甚至能比硬件的改进发挥更大的作用!这道题加深了我对算法重要性的认识。
输出输入改为c的格式是为了不#include<iostream>,可以节省一点内存,这样在用时相同的情况下,内存用的少的排名比较靠前嘻嘻
3.对除两端之外的字符做从内到外的扩散式搜索。AC,time=0.09s,memory=388k |
#include <stdio.h> #include <string.h> char str[5001]; int n,sum; void checkstr(int a,int b) { int hp,ep; if(a==b) { hp=a-1; ep=a+1; while(hp>=0 && ep<=n-1) { if(str[hp--]==str[ep++]) sum++; else { hp=-1; return; } } } else { hp=a;ep=b; while(hp>=0 && ep<=n-1) { if(str[hp--]==str[ep++]) sum++; else { hp=-1; return; } } } return; } int main() { int i; while(scanf("%s",str)!=EOF) { n=strlen(str); sum=n; for(i=1;i<n-1;i++) { checkstr(i,i); checkstr(i-1,i); } if(str[n-2]==str[n-1]) { sum++; } printf("%d/n",sum); } return 0; } |
相关文章推荐
- ZOJ 2744 Palindromes
- ZOJ 2744 Palindromes
- ZOJ 2744 Palindromes(动态规划)
- zoj 2744 Palindromes
- zoj_2744 Palindromes 回文
- zoj 2744 - Palindromes
- zoj2744 Palindromes 字符串的题
- zoj 2744 Palindromes(计算回文子串个数的优化策略)
- ZOJ 2744 Palindromes
- zoj 2744 Palindromes
- ZOJ Problem Set - 2744 Palindromes(字符串二分处理的好题)
- zoj 2744 - Palindromes
- zoj 2744 Palindromes
- zoj 2744 Palindromes (求回文子序列的个数)
- zoj 2744 Palindromes
- ZOJ 2744 Palindromes 区间DP
- zoj 2744
- HDU1318 POJ1590 UVA401 ZOJ1325 Palindromes【回文+水题】
- ZOJ 1325 Palindromes
- zoj 2744