005 Longest Palindromic Substring [Leetcode]

来源:互联网 发布:耀夜姬t恤淘宝 编辑:程序博客网 时间:2024/05/16 07:30

题目内容:

Given a string S, find the longest palindromic substring in S. You may assume that the maximum length of S is 1000, and there exists one unique longest palindromic substring.

解题思路:
比较直观的方法,就是以每个字符串为中心点,向前后同时遍历直到两边字符不同,并记录下字符长度。但这样无法处理字符串为偶数的情况。因此,我们可以先对字符串做一个处理,在每两个字符之间插入一个不会出现的字符,如‘#’,然后执行上述算法。

代码如下,这样的算法复杂度为O(n2)

class Solution {public:    string longestPalindrome(string s) {        int size = s.size();        if(size == 0 || size == 1)            return s;        size = size*2 + 1;        string str(size, '#');        for(int i = 1; i != size; i+=2)            str[i] = s[i>>1];        int maxR(0), max_index(0);        int *len = new int[size];        len[0] = 1;        int begin(0), end(0), temp(0);        for(int i = 1; i != size; ++i) {            temp = len[i-1]/2 + i-1;            maxR = maxR > temp ? maxR : temp;            begin = i;            end = i;            len[i] = 1;            while(begin != 0 && end != size - 1 && str[--begin] == str[++end])                len[i] += 2;            if(len[i] > len[max_index])                max_index = i;        }        string result = s.substr((max_index - len[max_index]/2)/2, len[max_index]/2);        delete[] len;        len = 0;        return result;    }};

在hiho中有对此题详细的解释。主要推导过程如下:

小Ho这一想就是三天,小Hi也是看不下去了,决定来开导开导小Ho:“小Ho,你有没有想过,在之前的计算中,计算出以每一个位置为中心的最长回文子串的长度有没有什么用呢?”

小Ho答道:“我想想,如果以第5个字符为中心的最长回文子串的长度是5的话,这就告诉了我[3, 7]这一段是一个回文子串,所以呢?”

小Hi继续提示道:“假设这时候你想要计算以第6个字符为中心的最长回文子串的长度,你有没有什么已知的信息了?”

小Ho边想边说道:“唔,首先第6个字符和第4个字符是一样的,第7个字符和第3个字符是一样的,而第5个字符本身就肯定和第5个字符一样,那么如果[3, 5]这一段是回文子串的话,那么[5, 7]这一段肯定也是回文子串。也就是说,如果令f[i] 表示以第i个字符为中心的最长回文子串的长度,我们就会有f[i] >= f[i–2]?”

“不对,还要考虑到f[i – 1]的值,如果f[i – 1]太小就没有意义了,应该是f(i)≥min⁡{f(i-2), f(i-1)-2}。”小Ho接着补充道。

“没错,但是还有一个问题,如果此时我告诉你f(5) = 1,但是f(4) = 7, f(2) = 3呢?”小Hi追问道。

小Ho想了想,回答道:“理论上来说,我可以通过这些信息知道f(6)>=3,但是由于f(5)=1所以我只能计算出来f(6)>=-1我知道了,我不应该是通过f(i – 1)来辅助计算,而是通过使得右边界(j + f(j) / 2)最大的那个j来辅助计算才是,所以公式将变成 f(i) ≥ min{f(2*j-i) , f(j) -2*(i-j)}这种形式了!”

小Hi继续问道:“那知道了这个公式之后,你打算怎么做呢?”

小Ho想也没想便道:“这简单,我只要在之前枚举中心位置那种方法的基础上,统计使得回文串右边界(j + f(j) / 2)最大的那个j,然后再计算每一个i的时候,都可以通过f(i)≥min⁡{f(2*j-i), f(j)-2*(i-j)}这个公式来知道f(i)的一个最小值,这样即使是在我们所提到的那种最坏情况下,也可以节省掉很多不必要的计算呢~

代码实现如下:

class Solution {public:    string longestPalindrome(string s) {        int size = s.size();        if(size == 0 || size == 1)            return s;        size = size*2 + 1;        string str(size, '#');        for(int i = 1; i != size; i+=2)            str[i] = s[i>>1];        int maxR(0), max_index(0);        int *len = new int[size];        len[0] = 1;        int begin(0), end(0), temp(0);        for(int i = 1; i != size; ++i) {            temp = len[i-1]/2 + i-1;            maxR = len[maxR]/2+maxR > temp ? maxR : i-1;            begin = i;            end = i;            len[i] = 1;            int temp1 = (maxR == 0 ? 1 : len[2*maxR - i]);            int temp2 = len[maxR] - 2*(i-maxR);            temp = (temp1 > temp2 ? temp2 : temp1);            if(temp > 1) {                begin = i - temp/2;                end = i + temp/2;                len[i] = temp;            }            while(begin != 0 && end != size - 1 && str[--begin] == str[++end])                len[i] += 2;            if(len[i] > len[max_index])                max_index = i;        }        string result = s.substr((max_index - len[max_index]/2)/2, len[max_index]/2);        delete[] len;        len = 0;        return result;    }};

还有的方法,推测可以使用后缀树来实现。

0 0
原创粉丝点击