5 Longest Palindromic Substring

给定一个字符串s,找出s中的最长回文串,假定s的最大长度是1000。

1. 暴力法(超时)

对于字符串s的每一个子串s[i,j),判断它是否是回文串,如果是,记下该字符串和它的长度,当遍历完所有的子串时,就可以找到满足要求的子串。

        public String longestPalindrome(String s)
	{
		String ans = null;
		int i = 0, j = 0;
		int maxlen = 0;
		String subStr = null;
		// 对于s的每一个子串,检查它是否是回文串 [i,j)
		for (j=0; j<s.length(); j++)
		{
			for (i=0; i<s.length(); i++)
			{
				if (i+j+1 >= s.length())
				{
					subStr = s.substring(i, s.length());
				}
				else
				{
					subStr = s.substring(i, i+j+1);
					System.out.println(subStr);
				}
				
				if (isPalindromicStr(subStr))
				{
					if (subStr.length() > maxlen)
					{
						maxlen = subStr.length();
						ans = subStr;
					}
				}
			}
		}
		return ans;
	}
	
	public static boolean isPalindromicStr(String subStr)
	{
		if (subStr.length() <= 1)
		{
			return true;
		}
		
		for (int i=0; i<subStr.length()/2; i++)
		{
			if (subStr.charAt(i) != subStr.charAt(subStr.length()-1-i))
			{
				return false;
			}
		}
		return true;
	}
	

时间复杂度:O(n^3) , n位字符串s的长度

空间复杂度:O(1)

2. 最长公共子串

一般来说,我们认为翻转字符串S得到S', 找出字符串S和S'的最长公共子串,这同样也是最长回文子串。

例如,S = "caba", S' = “abac”,最长公共子串是“aba",同样也是最长回文串。

但是,当在字符串S的中存在一个非回文的子串的反向拷贝时,该方法会失败。

比如:S="abacdfgdcaba", S' = "abacdgfdcaba",它们之间的最长公共子串是"abacd",但这并不是最长回文串。

为了纠正这一点,每当我们发现一个最长公共子串时的候选集时,我们需要检查该子串的索引是否与逆序后该子串的索引相同,

如果满足该条件,我们尝试更新到目前为止所发现的最长的回文串,否则的话,就跳过该串,继续寻找下一个候选者。

常规:Time Limit Exceeded  

	public String longestPalindrome(String s)
	{
		StringBuffer sBuffer = new StringBuffer(s);
		String reverse = sBuffer.reverse().toString();
		// 找出字符串s和字符串sBuffer的最长公共子串
		String common = getLongestSubString(s, reverse);
		return common;
	}
	
	
	/**
	 * 寻找字符串s1和字符串s2的最长公共子串
	 */
	public String getLongestSubString(String s1, String s2)
	{
		String common = ""; // 最长公共回文串
		int maxlen = 0; 
		int len = 0;  // 每一段公共子串的长度
		int i = 0, j = 0, m=0, n = 0;
		// 如果s1或s2是空串
		if (s1.isEmpty() || s2.isEmpty())
			return common;
		char[] array1 = s1.toCharArray();
		char[] array2 = s2.toCharArray();
		
		for (i=0; i<array1.length; i++)
		{
			for (j=0; j<array2.length; j++)
			{
				if (array1[i] == array2[j])
				{
					m = i;
					n = j;
					while ( m < array1.length && n < array2.length && array1[m] == array2[n])
					{
						len++; 
						// 这里需要对每一个公共子串进行判断
						if (len > maxlen)
						{
							// 判断该公共子串是否是回文串
							if (isPalindStr(s1.substring(i, m+1)))
							{
								common =  s1.substring(i, m+1);
								maxlen = len;
							}
						}
						// 更新两个数组比较的下标
						m++;
						n++;
					}
					len = 0; // 清零
				}
			}
		}
		return common;
	}
	
	/**
	 * 判断字符串s是否是回文串
	 */
	public boolean isPalindStr(String common)
	{
		// 检查该公共子串是否是回文串
		for (int i=0; i<common.length()/2; i++)
		{
			if (common.charAt(i) != common.charAt(common.length()-i-1))
			{
				return false;
			}
		}
		return true;
	}
	

采用动态规划来求解最长公共子串效率要高很多。

3. 扩展中心

一个回文串以它的中心对称,因此一个回文串可以从它的中心开始拓展,这样的中心共有2n-1个。

因为对称线除了是某个字母外,还有可能在两个字母之间。比如回文串“abba”。

        public String longestPalindrome(String s)
	{
		int start = 0, end = 0;
		for (int i=0; i<s.length(); i++)
		{
			// 以i作为对称中心进行拓展
			int len1 = expandAroundCenter(s, i, i);
			// 以i和i+1的中间作为对称中心进行拓展
			int len2 = expandAroundCenter(s, i, i+1);
			int len = Math.max(len1, len2);
			// 如果新找到的回文串长度比之前的要大
			if (len > end - start)
			{
				start = i - (len - 1) / 2;
				end = i + len / 2;
			}
		}
		return s.substring(start, end+1);
	}
	
	private int expandAroundCenter(String s, int left, int right)
	{
		int L = left, R = right;
		while (L>=0 && R < s.length() && s.charAt(L) == s.charAt(R))
		{
			L--;
			R++;
		}
		return R - L - 1; // 回文串的长度
	}

时间复杂度:O(n^2)

空间复杂度:O(1)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值