问题
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.
解法1:
O(N^2) 的算法复杂度的算法就不多说了,无非是遍历I,J,取得一个子串,并对这个字串进行判定,是否是回文串。遍历复杂度为O(N^2),判定复杂度为O(N)(前后指针),所以复杂度为O(N^2).
解法2:
http://leetcode.com/2011/11/longest-palindromic-substring-part-ii.html
根据他的解法,我能够理解他的想法,遍历一遍,取得中数,并向四周扩散,最后得出以此为中数,它最大能够扩充到多大。
当时我就有一个疑问:为什么要加#$^这些符号?
所以我打算不用符号实现一遍他的想法:
class Solution {
public:
string longestPalindrome(string s) {
int i =0;
int C = 0;
int R = 0;
int L = 0;
int i_mirror = 0;
/* init P */
int *P = new int[s.length()];
for (i = 0 ; i < s.length(); i++) {
P[i] = 0;
}
/* for every charactor */
for (i = 1 ; i < s.length() - 1; i++) {
i_mirror = 2*C - i;
P[i] = R > i ? min(R-i , P[i_mirror]): P[i];
int expand = (P[i] -1)/2;
while (1 ){
expand ++;
int leftExpandIndex = i - expand;
int rightExpandIndex = i + expand;
if (leftExpandIndex == 0 || rightExpandIndex == s.length() -1) {
expand --;
break;
}
if (s[leftExpandIndex] != s[rightExpandIndex]) {
expand --;
break;
}
}
P[i] = expand * 2 +1;
if (i + expand > R) {
C = i;
L = i - expand;
R = i + expand;
}
}
int maxLen = 0;
int centelIndex = 0;
for (i = 0 ; i < s.length(); i++) {
if(maxLen < P[i])
{
centelIndex = i;
maxLen = P[i];
}
}
int leftPosition = centelIndex - ((maxLen -1)/2);
return s.substr(leftPosition , maxLen);
}
最后我得出来的结论是,奇数回文数能够正确的被解答出来,而偶数的不行。所以在这里我就明白了,他为何要使用特殊符号了。
使用的用意很简单,举个例子:
1. 偶数个回文数:
#a#b#c#c#b#a#
其中以最中间的那个#为中数,左右分别有6个数,正好6 是 abccba 6个数。
2. 奇数个回文数:
#a#b#c#b#a#
其中以c为中数,分别左右有5个数,正好 abcba 也是5个数。
这是一个非常巧妙的解法,当我实现以上的算法的时候,坦白讲我也想再偶数回文数中塞一个数,我相信作者也是通过这个启发到最后他的解法。
修正之后的代码:
string translate(string s)
{
string rs("^#");
for (int i = 0; i < s.length(); i++) {
rs.push_back(s[i]);
rs.push_back('#');
}
rs.push_back('$');
//cout<<rs<<endl;
return rs;
}
class Solution {
public:
string longestPalindrome(string s) {
int i =0;
int C = 0;
int R = 0;
int L = 0;
int i_mirror = 0;
string rs= translate(s);
/* init P */
int *P = new int[rs.length()];
for (i = 0 ; i < rs.length(); i++) {
P[i] = 0;
}
/* for every charactor */
for (i = 1 ; i < rs.length() - 1; i++) {
i_mirror = 2*C - i;
P[i] = R > i ? min(R-i , P[i_mirror]): 0;
while (rs[i - P[i] -1] == rs[i + P[i] +1] ){
P[i]++;
}
if (i + P[i] > R) {
C = i;
L = i - P[i];
R = i + P[i];
}
}
int maxLen = 0;
int centelIndex = 0;
for (i = 0 ; i < rs.length(); i++) {
if(maxLen < P[i])
{
centelIndex = i;
maxLen = P[i];
}
}
int leftPosition = (centelIndex - 1 - maxLen)/2;
//cout<<maxLen<<endl;
return s.substr(leftPosition , maxLen);
}
};
分析
分析就不讲了,文中有提到,慢慢看。
总结
有时候需要通过添加某些辅助的数据来帮助自己简化逻辑。在第一个算法中其实可以加入偶数判定,也并非完全不可能实现,比较麻烦而已。