最长回文子串

一)简介

回文数:正着和反着读是一样的,例如:abccba;

回文子串:在一个字符串中,一串连续并且正着反着读是一样的字符。

例如:aattyyttdd中,aa、tt、ttyytt、yy、dd都是回文子串。

 

最长回文子串:在一个字符串中,回文子串最长的一串字符。

备注:每一个单独的字符本身就可以看作是一个回文数

 

二)最长回文子串

方式一:暴力法,执行时间复杂度是O(n^3),暂不考虑。

 

方式二:中心扩展法

原理:假设以每一个字符为中心,围绕该字符向左右两端探测比较。

分析:由于存在奇数的字符串和偶数的字符串,从一个字符扩展,总共有n+n-1个中心。

 

例如:aabccbad

1)先以第一个a为中心,向左右两边扩展,a的左方没有字符,本身就是回文子串。

2)再以第二个a为中心,向左右两边扩展,不是回文子串。

3)重复用每一个字符向左右两边扩展,只记录最长回文子串的信息。

 

中心扩展法源码:

/**
 * 中心扩展法: 最长回文子串
 * @param s
 */
public static String revertSubString(String s) {
	if (s == null || s.length() <= 0) {
		return null;
	}
		
	// 转换成字节数组
	char[] ch = s.toCharArray();
	int begin = 0; // 开始位置
	int end = 0; // 结束位置
		
	for (int i = 0; i < ch.length; i++) {
		int len1 = getLength(ch, i, i);
		int len2 = getLength(ch, i, i + 1);
		int maxLen = Math.max(len1, len2);
			
		// 计算开始位置和结束位置
		if (maxLen > end - begin) {
			begin = i - (maxLen-1) / 2;
			end = i + maxLen / 2;
		}
	}
		
	// 返回
	return s.substring(begin, end + 1);
}
	
private static int getLength(char[] ch, int left, int right) {
		
	// 左边界要大于等于0,右边界要小于字符串的长度,并且两个要相等,否则会死循环
	while (left >= 0 && right < ch.length && ch[left] == ch[right]) {
		left--;
		right++;
	}
	// 由于存在奇数的字符串和偶数的字符串,从一个字符扩展,总共有n+n-1个中心
		return right - left - 1;
}

 

方式三:动态规划法

1)先声明一个boolean[][] dp的二维数组,标识回文字符子串的连续路径,是回文数就标识为true。

2)用i表示终点,“j”表示起点

     若i==j,则dp[i][j]=true;

     若i和j是相邻的,则dp[i][j]=true;

     若i和j中间只有一个字符,则dp[i][j]=true;

     检查dp[j+1][i-1]是否为true,若为true,那么dp[i][j]就是true。

     前三条可以合并,即 j−i<=2。

3)记录最长回文子串的信息,并返回。

 

动态规划法源码:

/**
 * 动态规划: 最长回文子串
 * @param s
 * @return
 */
public static String lcsSubString(String s) {
	if (s == null) {
		return "";
	}
		
	char[] ch = s.toCharArray();
	int len = ch.length;
		
	boolean[][] dp = new boolean[len][len];
		
	int maxLen = 0; // 回文子串长度
	int start = 0; // 开始位置
	int end = 0; // 结束位置
		
	for (int i = 0; i < len; i++) { // i表示终点
		int j = i; // j表示起点
		
		while (j >= 0) {
			if (ch[i] == ch[j] && (i - j <= 2 || dp[j+1][i-1])) {
				dp[j][i] = true; // 如果是回文子串,标识为true
					
				// 最大长度,如果出现长度一样的字符串,取最后一个
				if (maxLen <= (i- j + 1)) {
					maxLen = (i- j + 1);
					start = j; // 开始位置
					end = i + 1; // 结束位置
				}
			}
			j--;
		}
	}
		
	// 返回
	return s.substring(start, end);
}

识别二维码关注个人微信公众号

本章完结,待续、欢迎转载!
 
本文说明:该文章属于原创,如需转载,请标明文章转载来源!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值