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

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

示例 1:

输入: "babad"
输出: "bab"
注意: "aba" 也是一个有效答案。
示例 2:

输入: "cbbd"
输出: "bb"

解题思路:

根据回文串的特性:我们知道一个字符串是回文那么同时去掉首尾一个字符仍然是回文(abcba同时去掉首尾的a,剩下的bcb仍然是回文),根据这个特性我们就可以列出他的状态转换方程。

我们设一个二维数组dp[i][j]来判断从下标 i 到下标 j 之间的字符串受否为回文.

要判断dp[i][j]是不是回文串需要先判断字符串两边的字符是否相等,如果相等判断dp[i+1][j-1]是不是回文串。

因为范围是i+1~~j-1;所以j-1-(i+1)+1>2,解得j-i<3;不满足那就说明越界或者不合法,之间忽视
(这里的串长度大于2,如果等于二就变成了判断dp[n][n]是不是回文串,自己本身就算,所以没什么意义)

举例:字符串arr="babc";下标为0~3

首先判断ba是否为回文,首先判断首尾是否相同,发现不同,那么ba这个子串的状态为false,所以bp[0][1]的状态为false;

然后判断bab是否为回文,首先判断首尾是否相同,相同则就同时去掉首尾然后判断剩下的子串是否为回文,去掉首尾剩下a,剩下的单个字符是回文,所以说明bab是回文,也就是说bp[0][2]的状态为true代表是回文。这时我们要记录这个回文串的长度maxlen,长度mexlen为j-1-(i+1)+1,把这个长度和原来的maxlen做对比取较大值,如果比原来的长那就说明原来的不是最长的我们做替换。同时需要记录回文的起始下标(根据长度和起始下标可以打印回文串)

然后判断ad是否为回文,首先ab的首尾不同,所以dp[1][2]的状态就是false,直接跳过

然后判断babc是否为回文,首先首尾不同,那么dp[0,3]状态为false,直接跳过

然后判断abc是否为回文,首先首尾不同,那么dp[1,3]状态为false,直接跳过

然后判断bc是否为回文,首先首尾不同,那么dp[2,3]状态为false,直接跳过

我们把所有的可能遍历完了,现在结果就是最长子串的长度就是maxlen,然后根据起始下标和长度打印出这个回文串。

下面给大家上正菜

#include<iostream>
#include<string>
#include<vector>
using namespace std;

class Solution {
public:string longestPalindrome(string s) {
		int len=s.size();
		if(len-2<0)
		{
			return s;
		}
		
		int maxlen=1;
		int begin=0;
		int **arr=new int*[len];//开辟一个二维数组保存状态
		for(int i=0;i<len;i++)
		{
			arr[i]=new int[len];
		}
		for(int k=0;k<len;k++)
		{
			arr[k][k]=1;
		}
		for(int j=1;j<len;j++)
		{
			for(int i=0;i<j;i++)
			{
				if(s[i]!=s[j])//判断首尾是否相同,不同则把状态定义为0;
				{
					arr[i][j]=0;
				}
				else//首尾相同时,就要去掉同时去掉首尾判断是不是为回文;
				{
					if(j-i<3)//判断边界,因为现在首尾相同,所以最少范围的长度无论是1或者2或者3都是回文,自己想想为什么
					{
						arr[i][j]=1;
					}
					else
					{
						arr[i][j]=arr[i+1][j-1];
					}
				}
				if(arr[i][j] && j-i+1>maxlen)//如果现在i~j下标的字符串是回文,且长度大于之前的回文长度时那么就要进行更新。
				{
					maxlen=j-i+1;
					begin=i;
				}
			}
		}
		return s.substr(begin,maxlen);
    }
};
int main()
{
	string arr="bb";
	Solution a ;
	string res="";
	res=a.longestPalindrome(arr);
	printf("%s\n",res.c_str());

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值