最长回文子串(动态规划)

要明确的一点是:一个长度大于等于3的回文串,去掉首尾两个字母以后,剩下的也是一个回文串。所以我们可以用 dp[ i ][ j ] = true OR false 来表示字符串第 i 个字符到第 j 个字符组成的串是否是回文串。
所以状态转移方程就是:
dp[ i ][ j ] = dp[ i + 1 ][ j - 1 ] && s[ i ] == s[ j ] (dp[ i + 1 ][ j - 1 ] 就是 dp[ i ][ j ] 去掉首尾字母以后的串)

以上的方程都是基于 i 到 j 组成的串长度是大于2的。那么串长度等于1或者2是怎么样的呢?
①当i 到 j 组成的串长度为 2 时,只要 s[ i ] == s[ j ],那么就是回文串,像:aa、bb、cc等。
②当i 到 j 组成的串长度为 1 时,是回文串。

故需要先初始化长度为1、2的回文子串,再由此基础上推导出长度为3或以上的串是否为回文串

整个算法的思路就是由低长度子串的回文性推导出高长度子串的回文性,长度为1、2的子串的回文性是需要先进行初始化的

 public class Palindrome {
 	public static void main(String[] args) {
 		Scanner sc = new Scanner(System.in);
 		String subStr = palindrome(sc.next);
 		System.out.println(subStr);
 	}
 	// 传入字符串,返回最长子串
 	String palindrome(String str) {
 		
 		if (str.length() == 0) {
 			return "";
		}
		int len = str.length();
		int startIndex = 0; // 最长子串开始下标
		int maxLen = 0;  // 最长子串的长度,可以结合开始下标 求子串结束下标的
		boolean[][] dp = new boolean[len][len];
		for (int strLen = 0; strLen < len; strLen++) { // 从长度为1的子串开始求起
			for (int i = 0; i + strLen < len; i++) { // 遍历子串的开始下标
				int j = i + strLen; // 子串的结束下标。则此时表示i 到 j 的长度为 strlen + 1的子串
				if (strLen == 0) { // 长度为1的子串,都是回文串
					dp[i][j] = true;
				} else if (strLen == 1) { // 长度为2的子串,只要两个字母相等,就是回文串
					dp[i][j] = (str.charAt(i) == str.charAt(j));
				} else {
					dp[i][j] = (dp[i + 1][j - 1] && str.charAt(i) == str.charAt(j));
				}
				if (dp[i][j]) {
					maxLen = strLen;
					startIndex = i;
				}
			}
		}
		return str.subString(startIndex, startIndex + maxLen + 1);
 }

外层循环是遍历所有的长度子串,所以子串长度 strLen 是从0 遍历到 len - 1。

内层循环是遍历确定长度子串的开始下标。所以开始下标 i 从 0 遍历到 i + strLen < len。

结束下标就是 j = i + strLen

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值