最长对称子串/回文串 简单动态规划

最长对称子串


7-32 最长对称子串 (300分)

       对给定的字符串,本题要求你输出最长对称子串的长度。例如,给定Is PAT&TAP symmetric?,最长对称子串为s PAT&TAP s,于是你应该输出11。


一、输入格式

       输入在一行中给出长度不超过1000的非空字符串。

二、输出格式

       在一行中输出最长对称子串的长度。

1.输入样例:

示例如下:

Is PAT&TAP symmetric?

2.输出样例:

11

三、思路:

       

1.暴力算法:

        根据对称子串的定义,我们考虑所有长度大于等于 2的子串,依次判断它们是否是回文串”;
        如果要输出回文串,可以只记录“当前子串的起始位置”和“子串长度,没有必要新建一个变量存储;
        复杂度高,但是容易理解。其他的解法也是基于这个方法;

#include<bits/stdc++.h>
using namespace std;

string s;
//子串 s[left, right] 是否为回文串
bool is_palindrome(int left, int right) {
    while (left < right) {
        if (s[left] != s[right]) {
            return false;
        }
        left++;
        right--;
    }
    return true;
}

int longestPalindrome() {
    //特判
    int l = s.size();
    if(l < 2) return l;

    int maxLen = 1;

    // 枚举所有长度大于等于 2 的子串
    for (int i = 0; i < l - 1; i++) {
        for (int j = i + 1; j < l; j++) {
            if (j - i + 1 > maxLen && is_palindrome(i, j)) {
                maxLen = j - i + 1;
            }
        }
    }
    return maxLen;
}

int main(){
	getline(cin , s);
	cout << longestPalindrome();
}

2.动态规划:

        1.动态规划核心是设计状态和状态的转移方程,也是最难的地方;
               对于一个回文串来说,去掉头和尾依然是回文串;
               如果一个字符串的头尾两个字符都不相等,那么此字符串不是回文串;
               如果里面的子串是回文,整体就是回文串;
               如果里面的子串不是回文串,整体就不是回文串。
所以说:当字符串头尾两个字符相等的时候,此字符串是否为回文串,只和此字符串的字串是否是回文串相关 这就是状态转移;
        2.状态的定义:

		dp[ i ][ j ] 表示子串 s[ i..j ] 是否为回文子串(左右都可以取到);

        3.状态转移方程:

		dp[i][j] = (s[i] == s[j] ? dp[i + 1][j - 1] : 0);

        4.说明:

我们要保证[i , j] 中 i <= j;并且当 i 和 j 相同时候表示一个字符本身,肯定是回文串;
	所以说初始化dp[i][i] = true 来表示是回文串。
当区间的长度是3或者2的时候,并且s[i] == s[j]这时候 字串[i , j] 一定是回文串,因为字串就一个字符或者是空,肯定是回文串
	所以当s[i]== s[j] 时候 字串的长度 (j - 1- (i + 1+ 1 < 2 的时候,
子串肯定是回文串,直接令 dp[i][j] = true即可;

        5.如果需要输出字符串,只需要记录最大字串的开始位置就行。

#include<bits/stdc++.h>
const int N = 1005;
using namespace std;

string s;
bool dp[N][N];
int ma = 1;
//int start;  //用来记录最长字串的开始下标
int deal(){
	int l = s.length();
	if(l == 0) return 0;
	if(l == 1) return 1;
	for(int i = 0 ; i < l ; i++){
		dp[i][i] = true;
	}
	for(int i = 1 ; i < l ; i++){
		for(int j = 0 ; j < i ; j++){
			if(s[i] != s[j]){
				dp[j][i] = false;
			}else{
				if(i - j < 3){
					dp[j][i] = true;
				}else{
					dp[j][i] = dp[j + 1][i - 1];
				}
			}
			//ma代表最大长度
			//是回文串并且长度大于最大的长度,更新最大长度回文子串
			if(dp[j][i] && i - j + 1 > ma){
				ma = i - j + 1;
//				start = j; //更新最大回文子串的起始下标
			}
		}
	}
	return ma;
}

int main(){
	getline(cin , s);
	cout << deal();
}
感谢阅读
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值