暴力
二层循环,分别控制子串的头部和尾部。然后再判断是否是回文串
class Solution {
public String longestPalindrome(String s) {
if(s.length()<=1》) return s;
int n=1;
int left=0;
int right=0;
for (int i = 0; i <s.length(); i++) {
//起点
for (int j = i+1; j <s.length(); j++) {
//终点
if(isH(i,j,s)&&j-i+1>n){
left=i;
right=j;
n=j-i+1;
}
}
}
return s.substring(left,right+1);
}
private boolean isH(int l,int r,String s){
//判断回文串
while (l<r){
if(s.charAt(l)!=s.charAt(r)) return false;
l++;
r--;
}
return true;
}
}
动态规划
回文串去掉首尾两个元素之后还是回文串。
P(i,j)=P(i+1,j-1)且s(i)==s(j)
class Solution {
public String longestPalindrome(String s) {
if (s.length()<=1) return s;
int n = 1;
int left = 0;
int right = 0;
boolean dp[][] = new boolean[s.length()][s.length()];
for (int r = 1; r < s.length(); r++) {
for (int l = 0; l < r; l++) {
if (s.charAt(r) == s.charAt(l) && (r - l <= 2 || dp[l+1][r-1])) {
dp[l][r]=true;
if (r - l + 1>=n) {
n = r - l + 1;
left = l;
right = r;
}
}
}
}
return s.substring(left, right + 1);
}
}
中心扩展算法
假设每一个元素都是回文串的中心,从中心用双指针向两边扩展。
扩展的时候这个回文串可奇可偶,要分开判断。
class Solution {
public String longestPalindrome(String s) {
if (s.length()<=1) return s;
int n = 1;
int left = 0;
int right = 0;
for (int i = 0; i < s.length()-1; i++) {
int oodlen=expand(s,i,i);
int evenlen=expand(s,i,i+1);
if(oodlen>evenlen){
if(oodlen>n){
n=oodlen;
left=i-n/2;
right=i+n/2;
}
}else{
if(evenlen>n){
n=evenlen;
left=i-(n-2)/2;
right=i+1+(n-2)/2;
}
}
}
return s.substring(left,right+1);
}
private int expand(String s, int l, int r) {
if(s.charAt(l)!=s.charAt(r)) return 1;
while (l<=r&&l>=0&&r<s.length()){
if(s.charAt(l)!=s.charAt(r)) break;
l--;
r++;
}
return r-l-1;
}
}
马拉车O(n)
在中心扩展算法的基础上,充分利用了回文串对称的特性。
马拉车算法的思想是在中心扩散的基础上减少重复判断——记录最新且边界最右回文子串的右边界和中心,那么根据回文的对称性,在该子串中心以右但不超出右边界的待验证子串可以用该子串中心以左的已验证子串来验证,超出右边界的待验证子串则进行朴素匹配。
class Solution {
public String longestPalindrome(String s) {
if(s.length()<=1) return s;
String sb=newString(s);
int rightSide=0;
int rightCenter=0;
int center=0;
int maxLen=0;
int op[]=new int[sb.length()];//记录回文串长度一半
for (int i = 0; i <sb.length(); i++) {
boolean flag=true;//是否中心扩展
if(i<rightSide){
int symmetricalIndex=2*rightCenter-i;//i关于rightCenter的对称点
op[i]=op[symmetricalIndex];
if(op[i]+i>rightSide){
//这里需要证明
op[i]=rightSide-i;
}
if(i+op[i]<rightSide){
flag=false;
}
//三种情况
//1.op[i]+i>rightSide -> op[i]=rightSide-i;,不许要扩展
//2.op[i]+i==rightSide ,需要扩展
//3.op[i]+i<rightSide -> op[i]=op[symmetricalIndex],不要扩展
}
if(flag){
while (i-1-op[i]>=0&&i+1+op[i]<sb.length()){
if(sb.charAt(i-1-op[i])==sb.charAt(i+1+op[i])){
op[i]++;
}else{
break;
}
}
//更新最右边界,于是中心也要改变。
rightSide=i+op[i];
rightCenter=i;
if(op[i]>maxLen){
//记录答案
maxLen=op[i];
center=i;
}
}
}
StringBuffer ans = new StringBuffer();
for (int i = center-maxLen+1; i <=center+maxLen; i+=2) {
ans.append(sb.charAt(i));
}
return ans.toString();
}
private String newString(String s) {
StringBuffer buffer = new StringBuffer();
buffer.append("#");
for (int i = 0; i <s.length(); i++) {
buffer.append(s.charAt(i));
buffer.append("#");
}
return buffer.toString();
}
}
比较难理解、
参考自:https://www.jianshu.com/p/116aa58b7d81
微信公众号-互联网侦查