LeetCode OJ 5. Longest Palindromic Substring

题目大意

  求一个字符串的最长回文子序列。


Manacher算法原理


首先,Manacher算法提供了一种巧妙地办法,将长度为奇数的回文串和长度为偶数的回文串一起考虑,具体做法是,在原字符串的每个相邻两个字符中间插入一个分隔符,同时在首尾也要添加一个分隔符,分隔符的要求是不在原串中出现,一般情况下可以用#号。下面举一个例子



原串: aaaabaa

转换后: @#a#a#a#a#b#a#a#a#$

Len数组有一个性质,那就是Len[i]-1就是该回文子串在原字符串S中的长度。首先在转换得到的字符串T中,所有的回文字串的长度都为奇数,那么对于以T[i]为中心的最长回文字串,其长度就为2*Len[i]-1,经过观察可知,T中所有的回文子串,其中分隔符的数量一定比其他字符的数量多1,也就是有Len[i]个分隔符,剩下Len[i]-1个字符来自原字符串,所以该回文串在原字符串中的长度就为Len[i]-1。有了这个性质,那么原问题就转化为求所有的Len[i]。



参考文献

http://larrylisblog.net/WebContents/images/LongestPalindrom.pdf


class Solution {
    public String longestPalindrome(String s) {
    		//Manacher算法求最长回文子串
    		//为了便于奇偶回文串同时处理
    		//预处理,将字符串中间添加特殊字符,e.g. aaaa -> @#a#a#a#a#$
    		StringBuilder newstring = new StringBuilder();
		newstring.append("@");
		
		for(int i = 0;i < s.length();i++){
			newstring.append("#");
			newstring.append(s.charAt(i));
		}
		newstring.append("#$");
		//System.out.println(newstring);
		
		//求回文半径
		int mx = 0;//记录当前求得的回文序列右端点的最大值
		int po = 0;//相应的该回文序列的中心
		int maxlen = 0;//最长回文半径
		int maxpo = 0;//最长回文中心
		
		//p[]存放的是回文子串的半径
		int[] p = new int[newstring.length()];
 		
		for(int i = 1;i < newstring.length()-1;i++){
			
			//类似于KMP算法,根据回文串的结构特点,避免重复运算
			p[i] = mx>i?Math.min(p[2*po - i], mx-i):1;
			
			while(newstring.charAt(i - p[i]) == newstring.charAt(i + p[i]))
				p[i]++;
			
			//更新数据
			if(p[i] + i > mx){
				mx = p[i] + i;
				po = i;
			}
			if(maxlen < p[i]){
				maxpo = i;
				maxlen = p[i];
			}
			//System.out.println(p[i]);
		}
		
		//System.out.println(anspo);
		
    		return s.substring(maxpo/2 - maxlen/2 , maxpo/2 + maxlen - maxlen/2 - 1);
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值