zoukankan      html  css  js  c++  java
  • 【算法】最长回文子串 longest palindrome substring

    对于字符串S, 要找到它最长的回文子串,能想到的最暴力方法,应该是对于每个元素i-th都向左向右对称搜索,最后用一个数组span 记录下相对应元素i-th为中心的回文子串长度。

    那么问题来了:

      1. 这样的方法,对于奇回文子串和偶回文子串的处理不一样,比如所“acbca” 和“acbbca”

      2. 计算冗余,e.g. ”sscssabcccchccccba“中, 自左向右遍历计算的话,会发现, ”abcccchccccba“是对称的,而这个回文字符串里又左右对称分别包含了两个回文子字符”cccc“和”cccc“, 在对第二个”cccc“字符串遍历的时候,其实可以利用到”abcccchccccba“的对称性来直接赋值,而不用再次计算

    于是,引出了Manacher's 算法:

      1. 为了可以对奇偶回文字符串不加区分地处理,对输入字符串增加边界元素(输入字符串S长度为N -> S2长度为2*N+1):e.g. ”aabbbcc“ -> "#a#a#b#b#b#c#c#" , ”aabbcc“ -> "#a#a#b#b#c#c#"

      2. 对于S2字符串,自左向右,每个字符逐个计算和处理

        1)用span[maxInputStringLength*2+1]数组来记录每个元素i-th为中心的回文字符串长度 : 初始化 span[0] = 0

        2)用center 和 rightBoundary 来记录上一个已知的回文字符串中心index和最右边界index :初始化 center = 0, rightBoundary = 0

        3)用 i 表示当前处理的元素, i2 表示 以 center 为中心的 center左侧 i 对称 元素下标 : i2 = center - (i - center)= center * 2 - i

        4)加上已知的回文子串信息之后,假设已经处理了S2[0, i-1]范围的元素,那么已知的回文子串中心center 必然属于[0, i-1]区间, 但是对于rightBoundary和i的关系可以有三种情况:

          a)当前处理的元素(index = i)以 center为中心,对称的元素(index = i2)上有,span[i2] < rightBoundary - i - 1, 表示i2点的回文字符串最左端不会超过leftBoundary的长度,利用了已知的回文字符串信息辅助说明,当前以i为中心的回文字符串将和i2完全对称,span[i] = span[i2]

          

          b)当前处理的元素(index = i)以 center为中心,对称的元素(index = i2)上有,span[i2] >= rightBoundary - i - 1, 表示 i2 点的回文字符串最左端已经超过了leftBoundary的范围,不能利用已知回文字符串直接赋值,但还是可以利用对称性,使得对称搜索从rightBoundary处开始,这样可以减少计算

          

          c)当前处理的元素(index = i)并不在已知回文串的记录范文内,那么久没有辅助信息,需要从i元素的左右对称搜索,得到span[i]的值

          

        5)最后要更新center和rightBoundary的值,使得已知回文字符串的覆盖范围右移,这样可以持续辅助搜索

      

     1 const int maxStringLength = 1000;
     2 
     3 string longestPalindrome(string s) {
     4 
     5     if (s.empty()) return "";
     6 
     7     ///add boundary
     8     string s2;
     9     for (int i = 0; i < s.size(); i++) {
    10         s2.push_back('#');
    11         s2.push_back(s[i]);
    12     }
    13     s2.push_back('#');
    14 
    15 
    16     /// setting
    17     int span[maxStringLength] = {0};
    18     span[0] = 0; // init the first element's length of palindrome
    19     int center = 0, rightBoundary = 0;
    20     int left = 0, right = 0;
    21 
    22     ///traverse 
    23     for (int i = 1; i < s2.size(); i++) {
    24         if (i <= rightBoundary) {
    25             int i2 = center * 2 - i;// center - (i - center)
    26             if (span[i2] < (rightBoundary - i - 1)) {
    27                 span[i] = span[i2];
    28                 left = -1;
    29             }
    30             else {
    31                 span[i] = rightBoundary - i;
    32                 right = rightBoundary + 1;
    33                 left = i * 2 - right; //i - (right - i)
    34             }
    35         }
    36         else {
    37             span[i] = 0;
    38             left = i - 1;
    39             right = i + 1;
    40         }
    41 
    42         while (left >= 0 && right < s2.size() && s2[left] == s2[right]) {
    43             span[i] ++;
    44             left--;
    45             right++;
    46         }
    47 
    48         if ((i + span[i]) > rightBoundary) {
    49             center = i;
    50             rightBoundary = i + span[i];
    51         }
    52     }
    53 
    54     /// find the max span length
    55     int maxSubstringCenter = 0, maxSubstringLen = 0;
    56     for (int i = 0; i < s2.size(); i++) {
    57         if (span[i] > maxSubstringLen) {
    58             maxSubstringLen = span[i];
    59             maxSubstringCenter = i;
    60         }
    61     }
    62 
    63     /// remove boundary '#' from substring
    64     string result;
    65     for (int i = maxSubstringCenter - maxSubstringLen; i <= maxSubstringCenter + maxSubstringLen; i++) {
    66         if (s2[i] != '#')
    67             result.push_back(s2[i]);
    68     }
    69 
    70     return result;
    71 }
    View Code
  • 相关阅读:
    每天一个linux命令(1):man命令
    安卓名词积累
    每天一个Linux命令:目录
    ubuntu下Python的安装和使用
    嵌入式基础知识(1):存储
    2月份学习笔记
    AndroidStudio 中的坑Error:(1, 0) Plugin is too old, please update to a more recent version, or set ANDROID_DAILY_OVERRID
    AndroidStudio开发出现Warning:Gradle version 2.10 is required. Current version is 2.8. If u
    Git 问题
    判断年 月的值
  • 原文地址:https://www.cnblogs.com/cheermyang/p/6674784.html
Copyright © 2011-2022 走看看