leetcode 5:Longest Palindromic Substring 三种解法的java实现源代码,以及详细讲解

题目分析:查找一个字符串中中最长回文字符串

1.算法1:暴力检索

   既然要查最长的回文字符串,那么直接对每一个字符,以它为中心,找到最长的回文字符串,更新最大值最小值就行了。注意要分两种情况,1
/**对每一个字母,都查找最大的回文串的长度,left,right分别表示回文串的起始位置*/
	public String longestPalindrome(String s) {
		int start = 0, end = 0;
		int maxLen = 1;
		for (int i = 0; i < s.length(); i++) {
			int left = i;
			int right = i;
			while (left > -1 && right < s.length()
					&& s.charAt(left) == s.charAt(right)) {
				left--;
				right++;
			}
			if (maxLen < right - left + 1) {
				maxLen = right - left + 1;
				start = left + 1;
				end = right - 1;
			}
			/**字符串长度为偶数*/
			left = i;
			right = i + 1;
			while (left > -1 && right < s.length()
					&& s.charAt(left) == s.charAt(right)) {
				left--;
				right++;
			}
			if (maxLen < right - left + 1) {
				maxLen = right - left + 1;
				start = left + 1;
				end = right - 1;
			}

		}
		return s.substring(start, end + 1);
	}

2. 动态规划

感觉第一个方法代码太多,而且很多重复计算,能不能之后的结果依据之前的结果,就想到了使用动态规划,主要是长度是慢慢扩展的,可以向依据长度变化的动态规划。
/**动态规划的思路,主要是考虑其实规划的时候是从内向外的扩展,主要考虑回文串的长度*/
	public String longestPalindrome(String s) {
		int start=0;
		int end=0;
		int max=1;
		int len=s.length();
		if(len<1) return "";
		if(len==1) return s;
		char[] a=s.toCharArray();
		boolean[][] dp=new boolean[len][len];
		/**长度为1和2*/
		for(int i=0;i<len;i++)
		{
			dp[i][i]=true;
			if(i<len-1&&a[i]==a[i+1])
			{
				dp[i][i+1]=true;
				if(max<2)
				{
					max=2;
					start=i;
					end=i+1;
				}
			}
		}
		/**这样设计循环的理由,其实我们规划的条件是len比较小的先算,再算len比较大的
		 * i为起始位置
		 * j为结束位置*/
		for(int l=3;l<=len;l++)
		{
			for(int i=0;i+l<=len;i++)
			{
				int j=i+l-1;
				if(a[i]==a[j])
				{
					dp[i][j]=dp[i+1][j-1];
					if(dp[i][j]&&l>max)
					{
						max=l;
						start=i;
						end=j;
					}
				}
				
			}
		}
		return s.substring(start, end+1);
	}

3. manacher算法

之上的两个算法都是o(n^2).然后搜索了一下,就发现被安利的manacher算法。先解释一下算法原理吧。算法主要是依据回文字符串的对称性来减少计算。
首先,为了消除诸如第一个算法中出现的奇数,偶数的影响,我们先进行一下预处理,在每一个字母之前都加一个#,这样每一个都为中心的都是回文串都是奇数个。为了防止处理中出现越界情况,所以我们可以在字符串的开始和结束加入特殊字符,比如(^$);
其次,为了更好的利用回文字符串的对称性,我们只需要对称字符串能够到达的最远位置r,以及对称中心cen.最后我们分情况讨论
假设对称中心为i,现在需要计算i+k位置,其对应位置为(i-k),P[i]为i向右延伸的回文串的长度
(1)i+k 大于r,那么之前的计算跟现在的没关系,只能仿照方法1计算
(2)i+k小于r 但是i+k+P[i-k]<r  根据对称性 P[i+k]=P[i-k];
  (3)i+k小于r,i+k+P[i-k]>=r   P[i+k]=r-(i+k)
源代码如下:
public String longestPalindrome(String s) {
		String str=prepare(s);
		int n=str.length();
		int cen=0;
		int r=0;
		int[] p=new int[n];
		char[] a=str.toCharArray();
		for(int i=1;i<n-1;i++)
		{
			int j=2*cen-i;
			p[i]=i<r?Math.min(r-i, p[j]):0;
			while(a[i+p[i]+1]==a[i-p[i]-1])
				p[i]++;
			if(p[i]+i>r)
			{
				cen=i;
				r=p[i]+i;
			}
		}
		/**找到长度最大的元素*/
		  int len = 0;
		  int centerIndex = 0;
		  for (int i = 1; i < n-1; ++i){
		    if(p[i] > len){
		      len = p[i];
		      centerIndex = i;
		    }
		  }
		  return s.substring((centerIndex-len-1)/2, (centerIndex+len-1)/2);
		
	}
	public String prepare(String s)
	{
		if(s.length()==0) return "^$";
		String ret="^";
		for(char c:s.toCharArray())
		{
			ret+="#"+c;
		}
		ret+="#$";
		return ret;
	}
	



    

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值