统计任意字符串中回文字符串的个数

来源:互联网 发布:为什么凌晨五点醒 知乎 编辑:程序博客网 时间:2024/05/29 17:36
 

统计任意字符串中回文字符串的个数

 545人阅读 评论(2) 收藏 举报
c++回文字符串阶乘

题目来源:

庞果英雄会

 

题目详情:

回文字符串是指从左到右和从右到左相同的字符串,现给定一个仅由小写字母组成的字符串,你可以把它的字母重新排列,以形成不同的回文字符串。 输入:非空仅由小写字母组成的字符串,长度不超过100; 输出:能组成的所有回文串的个数(因为结果可能非常大,输出对1000000007取余数的结果)。 例如:输入"aabb" 输出为2(因为“aabb”对应的所有回文字符串有2个:abba和baab) 函数头部 c: int palindrome(const char *s); c++ int palindrome(const string &s); java public static int palindrome(String s) ; 

 

题目分析:

1、统计输入字符串中每个字符出现的次数;

2、由于回文字符串左右对称,所以我只需要考虑以中心轴对称的一半就可以了。因此,可以将1中统计出的次数除以二;

3、这个问题就转换成了数学中的排列组合。即aaabbbbcccddd...一共有几种排列组合方法的问题。输入字符串长度除以二即为空位个

     假设为M。根据数学知识可得回文字符串的个数为M!/(M1!*M2!*M3!.......*Mn!),其中M1....Mn为每个字符重复出现的次数。

 

题目解答:

 

经过上述的分析,心想这还是挺简单的嘛,一看十分之一的正确率,心里还是挺得意洋洋的。也找了几个简单的例子来测,也都符合自己的预期,便提交了答案。一看自己的答题结果,血淋淋的测试未通过几个字眼摆在了我的眼前。下面将第一版的代码贴出来。

[cpp] view plaincopy
  1. unsigned long long int jieceng(int n)  
  2.  {  
  3.  unsigned long long int result=1;  
  4.  int i;  
  5.  for (i = 1; i <= n; i++)  
  6.  {  
  7.  result*=i;  
  8.  }  
  9.  return result;  
  10.  }  
  11.  int palindrome(const char *s)  
  12.  {  
  13.  int len = strlen(s);  
  14.  int num[26]={0};    
  15.  int flag_len = len % 2;  
  16.  int flag_bit;  
  17.  int num_bit[26]={0};  
  18.  int i;  
  19.  int block = len/2;  
  20.  unsigned long long int result;  
  21.  int flag=0;  
  22.  if (len > 100)  
  23.  {  
  24.  printf("Strings too long");  
  25.  return 0;  
  26.  }  
  27.  for (i = 0; i < len; i++)  
  28.  {  
  29.  num[*(s+i)-'a']++; //统计出每个字母出现的个数  
  30. }  
  31. for (i = 0; i < 26; i++)  
  32.  {  
  33.  flag_bit = num[i] % 2;  
  34.  if (flag_bit == 1)  
  35.  {  
  36.  flag++;  
  37.  }  
  38.  if ((flag_len == 0 && flag_bit == 1) || (flag_len == 1 && flag>1))  
  39.  {  
  40.  return 0;  
  41.  }  
  42.  num_bit[i] = num[i]/2;  
  43.  }  
  44.  result=jieceng(block);  
  45.  for (i = 0; i < 26; i++)  
  46.  {  
  47.  if (num_bit[i]==0)  
  48.  {  
  49.  continue;  
  50.  }  
  51.  result=result/jieceng(num_bit[i]);  
  52.  }  
  53.  result=result%1000000007;  
  54.  printf("Result is %d \n",result);  
  55.  return result;  
  56.  }  
  57.  int _tmain(int argc, _TCHAR* argv[])  
  58.  {  
  59.  char str[101] = "hqaymehhrsfuqrpahrimsxftuxqrpsejouuehaqtsryxjhearxmogmi";  
  60.  palindrome((const char *)(&str));  
  61.  return 0;  
  62.  }  

吃了闭门羹之后,很是郁闷,这不应该有什么问题啊。可能是自己缺少编程经验吧,调试了好一会儿才发现时求大数阶乘的时候会有溢出的问题。于是便寻找解决办法。也想了挺久的,其实没必要那么傻啊,没必要按照这个公式M!/(M1!*M2!*M3!.......*Mn!)先把每个数的阶乘算出来,可以拆成(1*2*3*...*N...M)/(M1!*M2!*M3!.......*Mn!),在遇到能约分的情况就约分,当分母全部被约掉之后,再判断这个时候的乘积是否大于1000000007,如果大于就取余。这样就不会有溢出的问题啦。所以有了第二版的代码。

[cpp] view plaincopy
  1. // ConsoleApplication2.cpp : Defines the entry point for the console application.  
  2. //  
  3. #include "stdafx.h"  
  4. #include "stdlib.h"  
  5. #include "string.h"  
  6. #include "stdio.h"  
  7.   
  8.   
  9. int jieceng(int n)  
  10. {  
  11.     int result=1;  
  12.     for (int i = 1; i <= n; i++)  
  13.     {  
  14.         result=result*i;  
  15.     }  
  16.     return result;  
  17. }  
  18.   
  19. int calc_result(int block, int *p)  
  20. {  
  21.     //int *pointer=(int *)malloc(block*sizeof(int));  
  22.     unsigned __int64 result_mid=1;  
  23.     unsigned __int64 result_mid_big=1;  
  24.       
  25.     for (int i = 1; i <= block; i++)  
  26.     {  
  27.         int sum=0;  
  28.         result_mid_big=result_mid_big*i;  
  29.         for (int j = 0; j < 26; j++)  
  30.         {  
  31.             sum+=*(p+j);  
  32.             if (*(p+j)==0)  
  33.             {  
  34.                 continue;         
  35.             }  
  36.             result_mid=jieceng(*(p+j));       
  37.             if (result_mid_big%result_mid==0)  
  38.             {  
  39.                 result_mid_big=result_mid_big/result_mid;  
  40.                 *(p+j)=0;  
  41.             }  
  42.         }  
  43.         if (sum==0)  
  44.         {  
  45.             if (result_mid_big>1000000007)  
  46.             {  
  47.                 result_mid_big=result_mid_big%1000000007;  
  48.             }  
  49.         }  
  50.     }  
  51.     return (int)result_mid_big;  
  52. }  
  53. int palindrome(const char *s)  
  54. {  
  55.     int len = strlen(s);  
  56.     if (len > 100)  
  57.     {  
  58.         printf("Strings too long");  
  59.         return 0;  
  60.     }  
  61.     int num[26]={0};    
  62.     int flag_len = len % 2;  
  63.     int flag_bit,flag=0;  
  64.     int num_bit[26]={0};  
  65.     for (int i = 0; i < len; i++)  
  66.     {  
  67.         num[*(s+i)-'a']++; //统计出每个字母出现的个数         
  68.     }  
  69.     for (int i = 0; i < 26; i++)  
  70.     {  
  71.         flag_bit = num[i] % 2;  
  72.         if (flag_bit==1)  
  73.         {  
  74.             flag++;  
  75.         }  
  76.         if ((flag_len == 0 && flag_bit == 1) || (flag_len == 1 && flag > 1))        //字符串长度为偶数,但是有出现基数词的字符,则不可能是回文字符  
  77.         {  
  78.             return 0;  
  79.         }  
  80.         num_bit[i] = num[i]/2;  
  81.     }  
  82.     int block = len/2;  
  83.     int result=calc_result(block,(int *)&num_bit);  
  84.     printf("Result is %d \n",result);  
  85.     return result;  
  86. }  
  87. int _tmain()  
  88. {  
  89.     char str[101] = "vlvdutxonuavcuwpkygenywmwofdubhhiqswkwgfbbbyjvlleqrrbmbkcfkqrpnyulzrkiwsbkauygajaqdybmxmqqcfygcdnty";  
  90.     palindrome((const char *)(&str));  
  91.     return 0;  
  92. }  

再一想,其实这样也还是有问题,只要用到了求阶乘的函数,就还是会有问题。在本题中,最多为100个字符,考虑一半,最多只有50个字符,每个字符出现的次数正常的话,也不会导致溢出。但是总是会有意外的啦,比如aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaan这样呢?上面的代码就死翘翘啦。所以我决定对代码进一步改进,摈弃阶乘这个函数。(1*2*3*....M)/(M1!*M2!*M3!.......*Mn!)在这个公式中,在分母中为了不进行阶乘运算,所以我决定统计出2、3.....max(M1,M2....Mn)出现的次数,分母一边进行乘法运算的时候,一边看能否整除2、3.....max(M1,M2....Mn),如果能整除,出现次数就减1,直到所有出现次数都为0时,判断此时的乘积是否大于1000000007,若大于则取余之后再进行乘法。依次类推。这形成下面第三版代码。

[cpp] view plaincopy
  1. // ConsoleApplication2.cpp : Defines the entry point for the console application.  
  2. //  
  3. #include "stdafx.h"  
  4. #include "stdlib.h"  
  5. #include "string.h"  
  6. #include "stdio.h"  
  7.   
  8. #define max(a,b) a>b?a:b  
  9.   
  10. int calc_result(int block, int *p,int len)  
  11. {  
  12.     unsigned __int64 result_mid=1;  
  13.     unsigned __int64 result_mid_big=1;  
  14.   
  15.     for (int i = 1; i <= block; i++)  
  16.     {  
  17.         int sum=0;  
  18.         result_mid_big=result_mid_big*i;  
  19.         for (int j = 2; j <= len; j++)  
  20.         {  
  21.             sum+=*(p+j);  
  22.             if (*(p+j)==0)  
  23.             {  
  24.                 continue;         
  25.             }  
  26.             if (result_mid_big%j==0)  
  27.             {  
  28.                 result_mid_big=result_mid_big/j;  
  29.                 (*(p+j))--;  
  30.             }  
  31.         }  
  32.         if (sum==0)  
  33.         {  
  34.             if (result_mid_big>1000000007)  
  35.             {  
  36.                 result_mid_big=result_mid_big%1000000007;  
  37.             }  
  38.         }  
  39.     }  
  40.     return (int)result_mid_big;  
  41. }  
  42. int palindrome(const char *s)  
  43. {  
  44.     int len = strlen(s);  
  45.     if (len > 100)  
  46.     {  
  47.         printf("Strings too long");  
  48.         return 0;  
  49.     }  
  50.     int num[26]={0};    
  51.     int flag_len = len % 2;  
  52.     int flag_bit,flag=0;  
  53.     int num_bit[26]={0};  
  54.     int MAX=0;  
  55.     for (int i = 0; i < len; i++)  
  56.     {  
  57.         num[*(s+i)-'a']++; //统计出每个字母出现的个数         
  58.     }  
  59.     for (int i = 0; i < 26; i++)  
  60.     {  
  61.         flag_bit = num[i] % 2;  
  62.         if (flag_bit==1)  
  63.         {  
  64.             flag++;  
  65.         }  
  66.         if ((flag_len == 0 && flag_bit == 1) || (flag_len == 1 && flag > 1))        //字符串长度为偶数,但是有出现基数词的字符,则不可能是回文字符  
  67.         {  
  68.             return 0;  
  69.         }  
  70.         num_bit[i] = num[i]/2;    
  71.         MAX = max(MAX,num_bit[i]);  
  72.     }  
  73.     int *p_num = new int[MAX+1]();  
  74.     for (int i = 0; i < 26; i++)  
  75.     {         
  76.         if (num_bit[i]<=1)  
  77.         {  
  78.             continue;         
  79.         }  
  80.         for (int j = 2; j <= num_bit[i]; j++)  
  81.         {  
  82.             (*(p_num+j))++;  
  83.         }  
  84.     }  
  85.     int block = len/2;  
  86.     int result=calc_result(block,p_num,MAX);  
  87.     printf("Result is %d \n",result);  
  88.     delete[] p_num;  
  89.     return result;  
  90. }  
  91. int _tmain()  
  92. {  
  93.     char str[101] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaan";  
  94.     palindrome((const char *)(&str));  
  95.     return 0;  
  96. }  

啊,总算可以歇口气了。我的代码还存在很多问题,希望路过的大侠们多给点建议,高手勿喷。

微信账号 forever19910521;

新浪微博 赶紧做毕设。

欢迎关注,那样可以多多交流嘛!

0 0
原创粉丝点击