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();
}