详细见:leetcode.com/problems/longest-palindromic-substring/
说明: manacher
Java Solution: github
package leetcode;
/*
* 假定存在唯一一个最长子序列
*/
public class P005_LongestPalindromicSubstring {
public static void main(String[] args) {
System.out.println(new Solution4().longestPalindrome("abad"));
}
/*
* 毫无疑问manacher(不会拼错了吧)
* 35.45%
* 特别慢
* 57ms
*/
static class Solution {
private final char sign = '#';
public String longestPalindrome(String s) {
if (s == null || s.length() == 0)
return "";
char[] m = new char[(s.length() << 1) + 1];
for (int i = 0; i != m.length; i ++)
m[i] = (i & 0x1) == 0 ? sign : s.charAt(i >>> 1);
int[] r = new int[m.length];
r[0] = 0; r[1] = 1;
int maxr = 2, core = 1, maxindex = 1;
for (int i = 2; i != m.length; i ++) {
if (i >= maxr) {
int newr = 1;
while (i > newr - 1 && i + newr < m.length && m[i + newr] == m[i - newr])
newr ++;
r[i] = newr - 1;
maxr = i + r[i];
core = i;
} else {
int j = (core << 1) - i;
if (r[j] + i < maxr) {
r[i] = r[j];
} else {
int newr = 1;
while (i > newr - 1 && i + newr < m.length && m[i + newr] == m[i - newr])
newr ++;
r[i] = newr - 1;
maxr = i + r[i];
core = i;
}
}
if (r[maxindex] < r[i])
maxindex = i;
if (maxr == m.length)
break;
}
StringBuilder st = new StringBuilder();
for (int i = maxindex - r[maxindex]; i != maxindex + r[maxindex] + 1; i ++)
if ((i & 0x1) == 1)
st.append(m[i]);
return st.toString();
}
}
/*
* 没有使用StringBuilder
* 40.94%
* 43 ms
*/
static class Solution2 {
private final char sign = '#';
public String longestPalindrome(String s) {
if (s == null || s.length() == 0)
return "";
char[] m = new char[(s.length() << 1) + 1];
for (int i = 0; i != m.length; i ++)
m[i] = (i & 0x1) == 0 ? sign : s.charAt(i >>> 1);
int[] r = new int[m.length];
r[0] = 0; r[1] = 1;
int maxr = 2, core = 1, maxindex = 1;
for (int i = 2; i != m.length; i ++) {
if (i >= maxr) {
int newr = 1;
while (i > newr - 1 && i + newr < m.length && m[i + newr] == m[i - newr])
newr ++;
r[i] = newr - 1;
maxr = i + r[i];
core = i;
} else {
int j = (core << 1) - i;
if (r[j] + i < maxr) {
r[i] = r[j];
} else {
int newr = 1;
while (i > newr - 1 && i + newr < m.length && m[i + newr] == m[i - newr])
newr ++;
r[i] = newr - 1;
maxr = i + r[i];
core = i;
}
}
if (r[maxindex] < r[i])
maxindex = i;
if (maxr == m.length)
break;
}
int len = m[maxindex] == sign ? ( (r[maxindex] + 1) >>> 1 ) << 1 : ( ( r[maxindex] >>> 1) << 1 ) + 1;
char[] ans = new char[len];
int j = 0;
for (int i = maxindex - r[maxindex]; i != maxindex + r[maxindex] + 1; i ++)
if ((i & 0x1) == 1)
ans[j ++] = m[i];
return new String(ans);
}
}
/*
* 不用m char 数组
* 75ms
* 27.05%
*/
static class Solution3 {
private final char sign = '#';
public String longestPalindrome(String s) {
if (s == null || s.length() == 0)
return "";
int len = (s.length() << 1) + 1;
int[] r = new int[len];
r[0] = 0; r[1] = 1;
int maxr = 2, core = 1, maxindex = 1;
for (int i = 2; i != len; i ++) {
if (i >= maxr) {
int newr = 1;
while (i > newr - 1 && i + newr < len && getIndexOfM(s, i + newr) == getIndexOfM(s, i - newr))
newr ++;
r[i] = newr - 1;
maxr = i + r[i];
core = i;
} else {
int j = (core << 1) - i;
if (r[j] + i < maxr) {
r[i] = r[j];
} else {
int newr = 1;
while (i > newr - 1 && i + newr < len && getIndexOfM(s, i + newr) == getIndexOfM(s, i - newr))
newr ++;
r[i] = newr - 1;
maxr = i + r[i];
core = i;
}
}
if (r[maxindex] < r[i])
maxindex = i;
if (maxr == len)
break;
}
len = getIndexOfM(s, maxindex) == sign ? ( (r[maxindex] + 1) >>> 1 ) << 1 : ( ( r[maxindex] >>> 1) << 1 ) + 1;
char[] ans = new char[len];
int j = 0;
for (int i = maxindex - r[maxindex]; i != maxindex + r[maxindex] + 1; i ++)
if ((i & 0x1) == 1)
ans[j ++] = getIndexOfM(s, i);
return new String(ans);
}
char getIndexOfM(String s, int i) {
if ((i & 0x1) == 0)
return sign;
else
return s.charAt(i >>> 1);
}
}
/*
* 41 ms
* 42.07%
*/
static class Solution4 {
private final char sign = '#';
public String longestPalindrome(String s) {
if (s == null || s.length() == 0)
return "";
char[] m = new char[(s.length() << 1) + 1];
for (int i = 0; i != m.length; i ++)
m[i] = (i & 0x1) == 0 ? sign : s.charAt(i >>> 1);
int[] r = new int[m.length];
r[0] = 0; r[1] = 1;
int maxr = 2, core = 1, maxindex = 1;
for (int i = 2; i != m.length; i ++) {
if (i >= maxr) {
int newr = 1;
while (i > newr - 1 && i + newr < m.length && m[i + newr] == m[i - newr])
newr ++;
r[i] = newr - 1;
maxr = i + r[i];
core = i;
} else {
int j = (core << 1) - i;
if (r[j] + i < maxr) {
r[i] = r[j];
} else {
int newr = 1;
while (i > newr - 1 && i + newr < m.length && m[i + newr] == m[i - newr])
newr ++;
r[i] = newr - 1;
maxr = i + r[i];
core = i;
}
}
if (r[maxindex] < r[i])
maxindex = i;
if (maxr == m.length)
break;
}
return s.substring((maxindex - r[maxindex]) >>> 1, (maxindex + r[maxindex]) >>> 1);
}
}
}
C Solution: github
/*
url: leetcode.com/problems/longest-palindromic-substring/
85ms 42.99%
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
char _access_char_array(char* s, int i) {
if (i % 2 == 0) return '\0';
return *(s + i / 2);
}
char* longestPalindrome(char* s) {
int n = strlen(s);
int ma_n = 2 * n + 1;
int ma_i = 0;
int ma_li = 0;
int ma_mi = 0;
int ma_mt = 0;
int l = 0, r = 0, i = 0, j = 0;
int * ma_r = NULL;
int ma_an = 0;
char * answer = NULL;
//manacher
ma_r = (int *) malloc(sizeof(int) * ma_n);
for (ma_i = 0; ma_i < ma_n; ma_i ++)
*(ma_r + ma_i) = 0;
for (ma_i = 0; ma_i < ma_n; ma_i ++) {
if (ma_mt >= ma_n - 1) break;
ma_mi = 2 * ma_li - ma_i;
if (ma_i >= ma_mt || (ma_i + *(ma_r + ma_mi) == ma_mt)) {
l = ma_i;
r = ma_i;
while ((l - 1) > -1 && (r + 1) < ma_n && _access_char_array(s, l - 1) == _access_char_array(s, r + 1)) {
l --;
r ++;
}
*(ma_r + ma_i) = (r - l) / 2;
ma_an = *(ma_r + ma_an) > *(ma_r + ma_i) ? ma_an : ma_i;
ma_li = ma_i;
} else if (ma_i <= ma_mt) {
*(ma_r + ma_i) = ma_mt - ma_i;
} else {
*(ma_r + ma_i) = *(ma_r + ma_mi);
}
}
answer = (char *) malloc(sizeof(char) * (* (ma_r + ma_an) + 1));
*(answer + *(ma_r + ma_an)) = '\0';
l = ma_an - *(ma_r + ma_an);
r = ma_an + *(ma_r + ma_an);
for (i = l; i <= r; i ++) {
if (i % 2 == 1)
*(answer + (j ++)) = _access_char_array(s, i);
}
free(ma_r);
return answer;
}
int main() {
char* s = "cbbd";
char* a = longestPalindrome(s);
unsigned int i = 0;
printf("len(a) is %d\r\n", strlen(a));
for (i = 0; i < strlen(a); i ++)
printf("%c", *(a + i));
printf("\r\n");
free(a);
return 0;
}
Python Solution: github
#coding=utf-8
'''
url: leetcode.com/problems/longest-palindromic-substring/
manacher
@author: zxwtry
@email: zxwtry@qq.com
@date: 2017年3月26日
@details: Solution: AC 632ms 41.14%
'''
class Solution(object):
def accessString(self, s, index):
if index % 2 == 0: return '#'
else: return s[index // 2]
def longestPalindrome(self, s):
"""
:type s: str
:rtype: str
"""
s_len = 0 if s == None else len(s)
if s_len == 0: return ""
m = [0] * (2 * s_len + 1)
m_last_i, m_mirror_r, m_max_touch_i, m_max_r_index = 0, 0, 0, 0
for i in range(2 * s_len + 1):
if m_max_touch_i >= 2 * s_len: break
m_mirror_r = m[2 * m_last_i - i]
if i >= m_max_touch_i or i + m_mirror_r == m_max_touch_i:
left, right = i, i
while left - 1 > -1 and right + 1 < 2 * s_len + 1 and \
self.accessString(s, left - 1) == self.accessString(s, right + 1):
left, right = (left - 1), (right + 1)
m[i] = (right - left) // 2
if m[m_max_r_index] < m[i]:m_max_r_index = i
m_last_i = i
m_max_touch_i = right
elif i + m_mirror_r < m_max_touch_i:
m[i] = m[2 * m_last_i - i]
else:
m[i] = m_max_touch_i - i
i = m_max_r_index // 2 - m[m_max_r_index] // 2
return s[i : i + m[m_max_r_index]]
if __name__ == "__main__":
s1="tabatabag"
s = Solution()
print("answer is \"%s\"" % s.longestPalindrome(s1))