• 回文串问题


    有关回文串的问题,可能涉及到判断一个字符串是否是回文串、求最大回文子串长度或者求至少添加多少个字符使得输入字符串称为回文串。这些问题我都已经解决,为了使用方便,我把这些实现代码都粘出来了。

      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 #include <string.h>
      4 
      5 /**
      6   * @brief 检测字符串是否为回文字符串,如果是,返回1;否则,返回0       
      7   */
      8 int isPalindrome(char s[], int len){
      9     int i, mid = len / 2;
     10 
     11     if (len == 1) return 1;
     12 
     13     for (i = 0; i < mid; i++){
     14         if (s[i] != s[len - i - 1])
     15             return 0;
     16     }
     17     return 1;
     18 }
     19 
     20 //穷举策略:O(n^3)
     21 int getMaxPalindrome1(char s[], int len, int *start)
     22 {
     23     printf("O(N^3) method.
    ");
     24     //offset是子串起始相对于输入字符串起始的偏移量,j是子串长度
     25     int offset = 0, j = len;
     26     int maxLen = 0;//存储回文子串的最大长度
     27 
     28     if (len <= 1) return -1;//出错
     29 
     30     while (offset < len){//子串起始逐个后移
     31         j = len - offset;//j初始化为可获得的最大子串长度
     32         while (j > 1){
     33             if (isPalindrome(s+offset, j)){
     34                 if (maxLen < j){
     35                     maxLen = j;
     36                     *start = offset;//记录最大子串的偏移
     37                 }
     38             }
     39             j--;//缩短子串    
     40         }
     41         offset++;//偏移量后移
     42     }
     43 
     44     return maxLen;    
     45 }
     46 
     47 //此算法仍然可以继续优化,在知道maxLen值的情况下,我们可以直接
     48 //寻找以offset为中心比maxLen大一个的长度来初始化left和right
     49 //的初始值,算法更加高效.
     50 int getMaxPalindrome2(char s[], int len, int *start)
     51 {
     52     printf("O(N^2) method.
    ");
     53 
     54     //奇数长度子串和偶数长度子串的最大回文长度
     55     int offset = 0, maxLen = 0, oddLen, evenLen;
     56     int left, right;//分别指向子串的左右边界
     57 
     58     if (len <= 1) return -1;
     59 
     60     while (offset < len){
     61         //奇数长度子串的情况
     62         left  = offset - 1;
     63         right = offset + 1;
     64         oddLen = 1;//初始化最大奇数回文长度为1
     65         //while (left >= 0 && right < len && isPalindrome(s+left, right-left+1)){
     66         while (left >= 0 && right < len && s[left] == s[right]){
     67             left--;
     68             right++;
     69             oddLen += 2;    
     70         }
     71         if (oddLen > maxLen){
     72             maxLen = oddLen;
     73             *start = ++left;
     74         }    
     75 
     76         //偶数长度子串的情况
     77         left  = offset;
     78         right = offset + 1;
     79         evenLen = 0;//初始化最大偶数回文长度为0
     80         //while (left >= 0 && right < len && isPalindrome(s+left, right-left+1)){
     81         while (left >= 0 && right < len && s[left] == s[right]){
     82             left--;
     83             right++;
     84             evenLen += 2;    
     85         }
     86         if (evenLen > maxLen){
     87             maxLen = evenLen;
     88             *start = ++left;
     89         }
     90 
     91         //偏移量自加
     92         offset++;
     93     }
     94 
     95     return maxLen;
     96 }
     97 
     98 // Manacher算法实现
     99 // 对原字符串进行预处理
    100 // srcstr[] 原字符数组 head:新串起始标志 separator:字符之间的分隔符
    101 char* prepare(char srcstr[], int len, char head, char separator)
    102 {
    103     int i, length = len;
    104     char *newstr = (char*)malloc(2*length + 3);
    105     newstr[0] = head;
    106     for (i = 0; i < length; i++){
    107         newstr[2*i+1] = separator;
    108         newstr[2*i+2] = srcstr[i];
    109     }
    110     newstr[2*length+1] = separator;
    111     newstr[2*length+2] = '';//添加结尾标志
    112 
    113     return newstr;//返回字符串起始地址
    114 }
    115 
    116 int getMaxPalindrome(char s[], int len, int *start)
    117 {
    118     char* newstr = prepare(s, len, '$', '#');//预处理
    119     int   maxLen = 0, length = strlen(newstr);  //新串长度
    120     int   i, mx = 0, pi = 1;//最长回文右边界mx和对称中心索引pi
    121     int*  p = (int*)malloc(length * sizeof(int));//辅助数组
    122 
    123     printf("O(N) method.
    ");
    124 
    125     p[0] = 0;//头标志$不统计回文串长度
    126     for (i = 1; i < length; i++){
    127         if (mx > i){//如果p[i]在最长回文串的范围内
    128             p[i] = ((mx - i) < p[2*pi - i]) ? (mx - i) : p[2*pi - i];
    129         }else{
    130             p[i] = 1;
    131         }
    132 
    133         while (newstr[i - p[i]] == newstr[i + p[i]] && i - p[i] > 0 && i + p[i] < length){
    134             p[i]++;
    135         }
    136 
    137         if (i + p[i] > mx){//如果新的最长回文串超出mx边界
    138             mx = i + p[i];
    139             pi = i;
    140         }
    141     }
    142     //寻找最大回文长度
    143     for (i = 1; i < length; i++)
    144     {
    145         if (p[i] > maxLen){
    146             maxLen = p[i];
    147             *start = (i-p[i])/2;//计算原串中最长回文子串起始索引
    148         }
    149     }
    150 
    151     free(newstr);
    152     free(p);
    153 
    154     return maxLen - 1;
    155 }
    156 
    157 //返回输入字符串应该添加至少多少个字符方可构成回文串
    158 int toPalindrome(char s[], int len)
    159 {
    160     char* re = (char*)malloc(len);//对s置逆
    161     int   cnt, i, j, temp, maxComm = 0;//两字符串的公共子串最大值
    162     
    163     for (i = 0; i < len; i++){
    164         re[len-1-i] = s[i];
    165     }
    166     //计算最长公共子串
    167     for (cnt = 0; cnt < len; cnt++){
    168         i = cnt; j = 0;
    169         temp = 0;
    170         while(i < len){
    171             if (s[i] == re[j]){
    172                 temp++;
    173                 i++; j++;
    174             }else{
    175                 if (temp > maxComm) 
    176                     maxComm = temp;
    177                 temp = 0;
    178                 j++;
    179             }
    180 
    181             if (j >= len){//如果其中一个字符串已经遍历一遍
    182                 if (temp > maxComm) 
    183                     maxComm = temp;
    184                 temp = 0;
    185                 j = 0;
    186                 i++;
    187             }
    188         }
    189     }
    190 
    191     return len - maxComm;
    192 }
    193 
    194 // for Test
    195 int main(void)
    196 {
    197     char  str[100];
    198     char* newstr = NULL;
    199     int  i, len, start = 0;
    200 
    201     fgets(str, sizeof(str), stdin);
    202     len = (int)strlen(str);
    203     if (str[len-1] == '
    '){
    204         str[len-1] = '';
    205         --len;
    206     }
    207     printf("Get: %s of size %d
    Answer: ", str, len);
    208 
    209 #if 0
    210     newstr = prepare(str, len, '$', '#');
    211     printf("new string: %s
    ", newstr);
    212     printf("new length: %d
    ", strlen(newstr));
    213     free(newstr); newstr = NULL;
    214 #endif
    215 
    216 #if 1
    217     printf(" Add %d
    ", toPalindrome(str, len));
    218 #endif
    219 
    220 #if 0
    221     if (isPalindrome(str, len)){
    222         printf("YES
    ");
    223     }else{
    224         printf("No
    ");
    225     }
    226     //最大回文子串
    227     len = getMaxPalindrome(str, len, &start);
    228     if (len > 1){
    229         printf("Max Palindrome String Length: %d
    ", len);
    230         for (i = 0; i < len; i++)
    231             printf("%c", str[start+i]);
    232         printf("
    ");    
    233     }
    234 #endif
    235 
    236     return 0;
    237 }
  • 相关阅读:
    mysql 5.7开启sql日志的配置
    Apache显示目录列表及icons目录的问题
    WebGL学习笔记二——绘制基本图元
    java上传文件类型检测
    binlog
    vs2015下C4819该文件包含不能在当前代码页(936)中表示的字符问题解决
    WebGL学习笔记一
    vs2015 debug时出现 C2039“cout”: 不是“std”的成员
    spring boot实现切割分片上传
    springboot自定义类@Resource注入为null的问题
  • 原文地址:https://www.cnblogs.com/xiaomanon/p/4470798.html
Copyright © 2020-2023  润新知