关于回文串的点点滴滴

  还是第一次发博文呢.嗯,最近在尝试每天做一道编程题,当然,我要求自己只能用C语言实现.一方面可增加自己对C函数库的熟悉程度,另一方面也想增加自身的编码经验.毕竟,感觉平时Code的时间严重不够.对于一个职业Coder来说这样肯定不太好嘛!

  好吧,回到正题吧.今天的题目内容很常规.就是判断用户输入的字符串是否是一个回文串,当然,难度稍微增加那么点,就是同时能够在一个字符串中找到所有的回文子串同时输出.想必,关于回文串的定义就没什么可说的了吧,比如"abba"就是个回文串,此外,还要能找出字符串"abc12321ddw"中的两个回文子串"12321"和"dd".自然,网上也有很多关于回文串判断的代码,但别人的代码终究不是自己写出来的,自然找不到感觉,所以就自己操练了一遍,好找一找感觉.

  好了,我将问题分成了两个部分来做:

  首先,我必须要能够判断一个字符串是一个回文串.那么回文串有什么特点呢?比如串"aba", "abba",仔细观察,会发现一些对称的特点.可以想象,手中有一张纸,我们现在要做的不过就是将这张纸给对折起来就好咯!所以,就有了下面的代码.我用它来判断字符串是否是回文串.当然,算法自然没什么优势,我对代码的追求是,首先它能运行,其次才是性能.

 1 //函数功能:判断一个字符串是否是回文串.
 2 //入口参数:str--指向字符串的指针
 3 //返回:1--是回文串,0--不是回文串
 4 int IsPalindromeString(const char* str)
 5 {
 6     assert(str != NULL);
 7 //    printf("%s\n", str);
 8     int flag = 1;
 9     int len = strlen(str);
10     int i_begin = 0;
11     int i_end = len - 1;
12     //如果长度为1,则fei回文串.
13     if (len <= 1)
14     {
15         flag = 0;
16     }
17     else
18     {
19     //想象将字符串进行折叠,若发现某个字符不重合,则判断一定不是回文串,否则是个回文串.
20         for (; i_begin <= i_end; i_begin++, i_end--)
21         {
22             if (tolower(str[i_begin]) != tolower(str[i_end]))
23             {
24                 flag = 0;
25                 break;
26             }
27         }
28     }
29     return flag;
30 }

查看代码

  好了,继续往下分析.我们以这样的一个字符串为例:"acd12321dfe",显然,我们很容易看出来中间的"12321"是个回文子串,但计算机可没那么聪明,那该怎么做呢?自然,我还是用了比较笨的办法咯.用两个游标i和j.这两个游标开始分别指向串首和串尾.然后,我们将从i开始到j结束的所有字符提取到一个临时串中并判断是否是回文串.通过不断地移动最终把所有的回文子串查找出来.

  自然而然地,我们显然要有个能够提取子串函数来完成字符串提取工作,于是就有了下面的函数咯,注意,我将一句话中可能存在的空格,标点符号等给忽略了,比如经典的回文语句"Able was I ere I saw Elba"很显然是个回文语句,所以,不能因为其中的空格或者大小写问题就造成误判:

 1 //函数功能:从源串中提取指定长度的子串到目的缓冲区保存
 2 //入口参数:dest--指向目的缓冲区的指针, src--指向源串的指针,start--起始位置,end--结束位置
 3 //返回:void
 4 void SubString(char* dest, const char* src, int start, int end)
 5 {
 6     assert(dest != NULL && src != NULL);
 7     //下面是一种比较笨的复制字符串的方法.
 8     //,.?! will not copy.
 9     int i = 0, j = start;
10     while (j <= end)
11     {
12         if (src[j] == ‘ ‘|| src[j] == ‘,‘ || src[j] == ‘.‘ ||
13             src[j] == ‘?‘ || src[j] == ‘!‘ || src[j] == ‘\‘‘)
14         {
15             j++;
16         }
17         else
18         {
19             dest[i++] = src[j++];
20         }
21     }
22 }

查看代码

  想一想,现在我们还需要一个查找一个字符串所有回文子串的函数了.于是便有了下面的函数.它用来接受用户输入的字符串,并将字符串中所有能构成的回文子串给打印出来.

  代码中,使用了malloc()函数申请了临时存储空间,用来存放每次用于测试的子串.算法估计算不上优,但是可正常工作了.

 1 //函数功能:查找一个字符串中所有的回文串并且打印出来
 2 //入口参数:str(指向一个字符串的指针)
 3 //返回:void
 4 void FindPalindromeSubString(const char* str)
 5 {
 6     assert(str != NULL);
 7     int len = strlen(str);
 8     int i = 0, j = 0, tmpPos = i, k = 0;
 9     //申请开辟一块缓冲区,用来存放测试串.
10     char* pBuff = (char*)malloc((len + 1) * sizeof(char));
11     if (pBuff == NULL)
12         return;
13
14     for (i=0; i<len; i++)
15     {
16         for (j=(len - 1); j>=tmpPos; j--)
17         {
18             if (str[i] == str[j])
19             {
20                 memset(pBuff, ‘\0‘, (len + 1) * sizeof(char));
21                 SubString(pBuff, str, i, j);
22                 if (IsPalindromeString(pBuff))
23                 {
24                     //当查找到回文子串时就打印出来.
25                     printf("#%d, length=%d: %s\n", ++k, (int)strlen(pBuff), pBuff);
26                     tmpPos = j + 1;
27                 }
28             }
29         }
30     }
31
32     if (k < 1)
33     {
34         printf("没有找到回文子串.\n");
35     }
36     free(pBuff);
37     pBuff = NULL;
38 }

查看代码

  好了,我们来看看main函数的实现代码吧,然后结束我们这个枯燥的话题吧^_^

 1 int main(void)
 2 {
 3     char ch[MAXLEN] = {‘\0‘};
 4     while (1)
 5     {
 6         memset(ch ,‘\0‘, MAXLEN * sizeof(char));
 7         printf("请输入字符串,程序将会输出所有的回文子串:\n");
 8         fgets(ch, MAXLEN * sizeof(char), stdin);
 9         FindPalindromeSubString(ch);
10         printf("\n");
11     }
12     return 0;
13 }

查看代码

  

  总结下,以上代码所使用的算法并非最优解,只代表我个人的解题思路,如果希望能找到更好的算法,CSDN的博客上也可以搜索到的.

  上面的代码,我在gcc4.8.2下编译并正常运行,来看看在Ubuntu14.04下测试的结果吧!

  顺便给Ubuntu做个广告吧!^_^,Good.

更改日志:

2014-4-28日,修改了FindPalindromeSubString()函数.第一,增加了一个判断,防止无意义的拷贝;第二,防止因为有类似"abcdcbabcdc"这样的重叠回文串判断错误!

  

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-12 04:00:36

关于回文串的点点滴滴的相关文章

最少回文串--牛客网(秋招备战专场三模)-C++方向

题目描述:一个字符串从左向右和从右向左读都完全一样则是回文串,给定一个字符串,问该字符串中的字符所能组成的最少的回文串的个数为多少 解题思路:如果一个字符出现的次数为偶数,则必能组成回文串,如果一个字符出现奇数次,只能自己组成回文串,题目中问最少的回文串数目,即求出现次数为奇数次的字符个数即可,定义a存储每个字符出现的次数,统计出现奇数次的字符的个数,即为输出 1 #include <iostream> 2 #include <string> 3 using namespace s

回文串问题

1.回文串的判断 #include <iostream> #include <string.h> using namespace std; //回文串的判断 bool isPalindrome(const char* src) { if(src == NULL) return true; int end = strlen(src)-1,begin = 0; while(begin < end)//从两边向中间判断,当然也可以从中间向两边判断 { if(src[begin] !

bzoj 2565: 最长双回文串

Description 顺序和逆序读起来完全一样的串叫做回文串.比如acbca是回文串,而abc不是(abc的顺序为"abc",逆序为"cba",不相同).输入长度为n的串S,求S的最长双回文子串T,即可将T分为两部分X,Y,(|X|,|Y|≥1)且X和Y都是回文串. Input 一行由小写英文字母组成的字符串S. Output 一行一个整数,表示最长双回文子串的长度. Sample Input baacaabbacabb Sample Output 12 HINT

BZOJ2565:最长双回文串

2565: 最长双回文串 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2195  Solved: 1119[Submit][Status][Discuss] Description 顺序和逆序读起来完全一样的串叫做回文串.比如acbca是回文串,而abc不是(abc的顺序为"abc",逆序为"cba",不相同). 输入长度为n的串S,求S的最长双回文子串T,即可将T分为两部分X,Y,(|X|,|Y|≥1)且X和Y都

Power oj/2610[判断回文串]

题目链接[https://www.oj.swust.edu.cn/problem/show/2610] 题意:给你一个字符串,让你判断这个字符串是不是回文串,字符串的长度是1<len<1e7,内存是4096KB. 题解:首先这1e7个字符是存不下的,1e71024=9765KB>4096kB.那么怎么办?字符串哈希,先对字符串的前半部分进行哈希,然后在对字符串后半部分进行哈希,如果两部分的哈希值相同,那么这个字符串就是回文串. BKDRH哈希,哈希公式为has=has*seed+s[i]

409.求最长回文串的长度 LongestPalindrome

题目要求求出长度即可,并不需要求出最长回文串. 思路:用字典统计每一个字符的出现次数,出现次数大于1的字符必定出现在回文串中,另外还再加上一个中心点. public static int LongestPalindrome(string s) { int length = 0; Dictionary<char, int> dictionary = new Dictionary<char, int>(); int value = 0; foreach (char c in s) {

[haoi2009]求回文串

所谓回文串,就是对于给定的字符串,正着读和反着读都一样,比如ABCBA就是一个回文串,ABCAB则不是.我们的目标是对于任意输入的字符串,不断将第i个字符和第i+1个字符交换,使得该串最终变为回文串.求最少交换次数. 题解: 有一种做法是贪心: 就是每次找到最左端的字符,然后找到这序列中最右边的一样的字符,然后把这个字符移过去,然后把最左端右移,继续以上操作: 最后的答案就是每次的移动步数加起来: 要吐槽的是,window下I64d不要忘了...... #include<iostream> #

字符串(马拉车算法,后缀数组,稀疏表):BZOJ 3676 [Apio2014]回文串

Description 考虑一个只包含小写拉丁字母的字符串s.我们定义s的一个子串t的“出 现值”为t在s中的出现次数乘以t的长度.请你求出s的所有回文子串中的最 大出现值. Input 输入只有一行,为一个只包含小写字母(a -z)的非空字符串s. Output 输出一个整数,为逝查回文子串的最大出现值. Sample Input [样例输入l] abacaba [样例输入2] www Sample Output [样例输出l] 7 [样例输出2] 4 HINT 一个串是回文的,当且仅当它从左

LightOJ1258(线性回文串

题目:给出一个序列,求最少在后面加多少字符形成一个回文串. 思路:裸的manacher,注意枚举的起点和终点. /* * @author: Cwind */ ///#pragma comment(linker, "/STACK:102400000,102400000") #include <iostream> #include <map> #include <algorithm> #include <cstdio> #include &l