C++接收字符串数组_动态规划-最长回文字符串

给定一个字符串s,找到s中最长的回文子串。你可以假设s的最大长度为1000。

示例1:

输入: "babad"

输出: "bab"

注意: "aba"也是一-个有效答案。

示例2:

输入: "cbbd"

输出: "bb"

这是一道非常经典的动态规划的题目,我是在回顾算法题的时候看到这一题,我记得我以前做过,但是理解不深,所以当时我怎么想都想不出来,于是乎看了看官方题解,然后写下本篇文章。

思路:官网上的p[i][j]啊啥的我就不说了,我使用大白话让你理解,比如现有一个字符串为"dcabace",现不用程序去跑,肉眼观察,你扫描一圈,发现了aba是回文字符串,接下来你一定是从aba开始,看到这个是最小回文字符串,然后扩大,看看c是不是在"aba"两端都有,如果有,那么这个回文字符串就大了一圈,现在顺着这个思路,如果你能在程序中知道最小回文字符串,是不是就可以慢慢扩大范围找出更大的呢? 答案是肯定的!

找出长度为3的最小回文字符串代码如下:

思路:当遇到两个相同字符时,查看这两个字符位置下标差是否小于3,如果是,则返回。

public 

在我找到最小回文串之后,我扩大一圈,查看更大的回文串的时候,这个时候我就慌了,我脑子能记住刚刚扩容之前的那个字符串,可是程序记不住啊,所以我们需要一个flag,来标记上一个字符串所在位置,为回文字符串,这个时候我判断结束之后,我就去查看我上一个位置是不是回文,如果是,我就可以扩容,如果不是,则不扩容。

public static String longestPalindrome(String s) {
	int len = s.length();
        String str = new String();
	boolean[] flag = new boolean[len];
	for(int i = 0 ; i < len ; i++) {
		for(int j = 0 ; j <= i ; j++) {
			flag[j] = (s.charAt(i) == s.charAt(j)) && (i - j < 3 || flag[j + 1]);
			if(flag[j] && i - j + 1 > str.length()) {
				str = s.substring(j, i + 1);
			}
		}
	}
	return str;
}

理解这个flag数组是不容易的,画图演示:

当我们的字符串是 "dcabac" 这样的,遍历的时候i到了最后的位置,j从头开始遍历,当j在0号位置的时候,不成立,j++。

eccdcff542ab2302a7e6da4d9b71cf58.png

此时到达这个位置(如下图所示),我们人为思考知道这一个就是最大回文串,而且这段代码确实是判断出来了,为什么呢?

9e02d38179cb0b44b9ae11bd018fd66a.png

核心代码

 flag[j] = (s.charAt(i) == s.charAt(j)) && (i - j < 3 || flag[j + 1]);

显而易见,这个flag[j] 程序一定是判断为true,才可能会输出这个字符串,那么为什么是true? 看第一个条件

(s.charAt(i) == s.charAt(j))

没错,这个是true,然后看下一句

(i - j < 3 || flag[j + 1])

i - j < 3 显然为false,断定 flag[j + 1] 一定为true,问题就在这里,flag[j + 1]是什么,它为什么是true?

我画图演示,行代表这个boolean数组的取值,列代表 i 循环次数。

21e0d627b1acdcb2de09ba914b4e92c8.png

第五次后面五个全是T的原因为第四次后面三个是T,flag[j + 1]为true,i = 5此次循环,当 j = 1 时,虽然这两个元素相等,但是之间距离大于3,但是!!flag[j + 1] 为true,所以验证成功,因为flag[j + 1] 在上一次我们就已经验证过它是回文串了。照这个思想继续下去,我们每验证到有两个字符相同,就去找它下一个下标,是否曾经判断过为回文串,是的话,扩容,以此循环,就可以找出最大回文字符串,可能你会问,不是应该用二维数组装吗?你可以debug试一试,flag[]这个数组他后面的值不会被替换,j+1还是能访问到,也就是说,你这一次进循环还是可以访问到上一次的值,以此达到判断上一个串的效果,至此,解答结束。

谢谢!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值