Leetcode---Longest Palindromic Substring
2016-09-29 15:04
453 查看
最长回文字串(Longest Palindromic Substring)
题目: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.
题目连接:https://leetcode.com/problems/longest-palindromic-substring/
大意是给定一个字符串S,求S中最长的回文字串,回文字符串是指从坐到右和从右到左都是一样的字符串,例如:“西湖回游鱼游回湖西”、“ABDCDBA”、“abccba”等等诸如此类的字符串,单个字符的串,也是回文串。
思路1:暴力解法,枚举S的所有字串,判断每个字符串是否是回文串,返回最长的串,当字符串很长的时候,枚举也只能想想了,更别说还要判断是否是回文。
思路2:枚举中心法,我们感兴趣的只是串中的回文字串,因为回文串的性质,那么我们可以枚举串中每一个字符,来检查以它为中心的串是不是回文串,并选取其中最长的返回。
例如:ABDCDBA
1.以A为中心,A的左边没有字符,所以只能是A当作一个回文。
2.以B为中心,那么比较B的左边和右边字符是否相等。相等,是回文。否则,不是。
3.以此类推,直到所有的字符作为中心判断完。
假设以i为中心,j为i左右的长度,且满足条件1:(i-j)>=0 && (i+j)<S.size(); j从0开始,到不能满足条件1结 束,分别判断,判断完成以i为中心后,以i+1为中心再进行类似判断。当然还有一个问题,就是回文串的长度有 可能是奇数,也可能是偶数。例如ABA、ABBA都是回文。这个时候只需要对奇数还是偶数进行分别判断:
奇数时:判断S[i-j] == S[i+j],j满足(i-j)>=0 && (i+j)<S.size()。
偶数使:判断S[i-j] == S[i+j+1],j满足(i-j)>=0 && (i+j+1)<S.size()
CODE:
string LongestPalindrome( string s) { int start=0,maxLen = 1,tlen = 1,ti=0; int size = s.size(); if( size <= 1 ) return s; // 奇数 for( int i = 0; i < size; i++) { for( int j = 0; (i-j>=0) && (i+j= maxlen ) { maxlen = tlen; start = i-j; } // 偶数 for( int j = 0; (i-j>=0) && (i+j+1 <= n); ++j ) { if( s[i-j] != s[i+j+1]) break; tlen = 2*j+2; ti = i-j; } if(tlen > maxlen ) { maxlen = tlen; start = ti; } } return s.substr(start,maxlen); }
思路3:先看下面的例子:
A AABABBAABCBABC
....
可以看出什么? A按规定是一个回文,要判断BAB是不是回文,那么判断B==B,且A是不是回文。判断BAAB,则判断B==B? 且AA是不是回文。以此类推,可以总结 到:
1.单个字符是回文。
2.两个字符相同是回文,否则不是。
3.长度大于等于3的串,满足s[0]==s[s.size-1] && s.substr(1,s.size-2)是不是回文。满足则是,否则不是。
更一般化来讲:
对于以i为起点,j为长度的string是不是回文串,只需要判断,s[i]==s[s+j-1]且s[i+1 to i+j-2]之间的串是不是回文串,这样问题规模就减小了,对于规模 大的问题转换到小规模问题求解,那么很容易想到的就是动态规划。
DP[i][i] = true; i<s.size();
DP[i][i+1] = true; if( s[i]==s[i+1] && i<s.size()-1)
DP[i][j] = true; if( s[i]==s[j] && DP[i+1][j-1] && i<size & j < size)
按照这个思路很自然可以得出代码:
CODE
string longestPalindrome(string s) { const int size = s.size(); if( size == 1) return s; bool dp[1000][1000] ; for( int i = 0; i < 1000; i++) memset(dp[i],false,1000); int maxlen =1; int start = 0; for( int i = 0; i < 1000; i++) { dp[i][i]= true; if( i<(size-1) && (s[i] == s[i+1])) { dp[i][i+1]=true; start = i; maxlen = 2; } } for( int len = 3; len <= size; len++) { for(int i = 0; i < size-len+1; i++) { int j = i+len-1; if( dp[i+1][j-1] && (s.at(i)==s.at(j))) { dp[i][j] = true; start = i; maxlen = len; } } } if( maxlen >= 2) { return s.substr(start,maxlen); } return NULL; }
抛开暴力枚举的方法,因为效率太低了,中心枚举和动态规划的时间复杂度都是O(n^2),还有没有更高效的方法呢?当然有,这就是传说中的Manacher算法,这个方法需要点想象力啊。
思路4:Manacher算法,这就是个传说。Manacher算法思想是来自上述“中心扩展法”,在“中心法”中要考虑回文
串是奇数还是偶数,有没办法统一处理呢?有,这就是Manacher算法。
该算法首先将字符串的每个字符之间加入一个特殊字符,并且在字符串开头加入一个标志来更好处理越界和编码问题。例如:s=“abba”编码后是:s=“$#a#b#b#a#”。
然后,用一个数组p来记录每个字符是s[i]为中心的的回文串向左或向右的长度,则原字符串s的回文长度为max(p[i]-1)。因为对于一个回文字符串s加入特殊字符后,该回文串加上特殊字符后依然会是一个回文串,且编码后的回文串的长度为2*s.size+1。那么数组记录的最大值为s.size+1,比原回文的长度多1。故求取p[]的最大值减1就是原字符串中最大的回文串。
现在最重要的问题就是怎么求解p[],这似乎又回到原来开始的问题了,非也。因为加了特殊字符,会出现一些有用的结论。
假设现在求p[i]的值,则p[0]...p[i-1]的值已经求出,maxlen为目前已经求出的回文串延伸到右边的最大长度,id为p[0]到p[i-1]最大回文串的中心,j为i关于id的对称点,即j=2*id-i。那么:
1.如果i不在maxlen范围内,即不在任何回文串中,则p[i]=1(本身为回文)。接着判断p[i+j]==p[i-j],为真则++p[i],否则2;
2.p[i]>=min(p[2id-i],maxlen-i]。
证明:
情况1:
情况2:
情况3:
int Manacher(string s) { int len = s.size(); int maxLen = 0; int id; int mx = 0; for (int i = 1; i < len; i++) { if (i < maxLen) p[i] = min(p[2 * id - i], maxLen - i); else p[i] = 1; while (s_new[i - p[i]] == s_new[i + p[i]]) p[i]++; if (maxLen < i + p[i]) { id = i; maxLen = i + p[i]; } mx = max(mx, p[i] - 1); } return mx; }
相关文章推荐
- LeetCode(5) Longest Palindromic Substring
- Longest Palindromic Substring leetcode
- [LeetCode 解题报告]005.Longest Palindromic Substring
- #leetcode#Longest Palindromic Substring
- LeetCode 005 Longest Palindromic Substring
- LeetCode-Algorithms #005 Longest Palindromic Substring, Database #180 Consecutive Numbers
- leetcode 5-Longest Palindromic Substring
- Leetcode-Longest Palindromic Substring
- LeetCode:Longest Palindromic Substring
- *LeetCode-Longest Palindromic Substring
- leetCode Longest Palindromic Substring
- leetcode--Longest Palindromic Substring
- leetcode 5 :Longest Palindromic Substring 找出最长回文子串
- LeetCode:Longest Palindromic Substring
- Leetcode: Longest Palindromic Substring
- leetcode 5 -- Longest Palindromic Substring
- LeetCode题解(Golang实现)--Longest Palindromic Substring
- 【Leetcode】Longest Palindromic Substring
- leetcode problem (5) Longest Palindromic Substring
- LeetCode Longest Palindromic Substring