问题
Given a string, you are supposed to output the length of the longest symmetric sub-string. For example, given Is PAT&TAP symmetric?, the longest symmetric sub-string is s PAT&TAP s, hence you must output 11.
Input Specification:
Each input file contains one test case which gives a non-empty string of length no more than 1000.
Output Specification:
For each test case, simply print the maximum length in a line.
Sample Input:
Is PAT&TAP symmetric?
Sample Output:
11
解决方法
题目大意
就是求一个字符串里面最长回文字符串。
思路
暴力解法
这种解法是因为测试点对时间的要求比较和蔼,所以能过。要是稍微苛刻一点,不能全部AC…
#include<iostream>
#include<string>
using namespace std;
bool issymmetric(int start, int end, string s)
{
for (int i = start; i <= (end+start)/2+1; i++)
{
if (s[i] != s[end--]) return false;
}
return true;
}
int main()
{
string s;
int len=0, maxlen=1;
getline(cin, s);
for (int i = 0; i < s.size(); i++)
{
for (int j = i + 1; j < s.length(); j++)
{
if (issymmetric(i, j, s)) len = j - i+1;
if (len > maxlen) maxlen = len;
}
}
printf("%d", maxlen);
return 0;
}
dp
LCS
分析:在经典的LCS中:
dp[i][j]是A1…Ai和B1…Bj对应的LCS长度。对于dp[i+1][j+1]:
♦A[i+1]=B[j+1] dp[i+1][j+1]=dp[i][j]+1
♦A[i+1]!=B[j+1] dp[i+1][j+1]=max(dp[i+1][j],dp[i][j+1])
而此题则可以说是求两个字符串(原来的字符串翻转后和本身)的最长相同子串问题.关系式变成如下:
当A[i+1]=B[j+1] dp[i+1][j+1]=dp[i][j]+1
当A[i+1]!=B[j+1] dp[i+1][j+1]=0
不相同的字符加上去后,就会导致字符串不相等。
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
int dp[1005][1005] = { 0 }, maxn = 1;
int main()
{
string s1, s2;
getline(cin, s1);
s2 = s1;
reverse(s1.begin(), s1.end());
for (int i = 0; i < s1.size(); i++)
{
for (int j = 0; j < s2.size(); j++)
{
if (s1[i] == s2[j])
{
dp[i + 1][j + 1] = dp[i][j] + 1;
maxn = max(maxn, dp[i + 1][j + 1]);
}
else dp[i + 1][j + 1] = 0;
}
}
printf("%d", maxn);
return 0;
}
直接dp
分析:dp[i][j]表示s[i]到s[j]所表示的字串是否是回⽂字串。只有0和1,递推⽅程为:
1 当s[i] == s[j] : dp[i][j] = dp[i+1][j-1]
2 当s[i] != s[j] : dp[i][j] =0
3 边界:dp[i][i] = 1, dp[i][i+1] = (s[i] == s[i+1]) ? 1 : 0
⾸先初始化dp[i][i] = 1, dp[i][i+1],把⻓度为1和2的都初始化好,然后从L = 3开始⼀直到 L <= len 根据动态规划的递归⽅程来判断(参考柳神)
#include<iostream>
#include<string>
using namespace std;
int dp[1010][1010] = { 0 }, maxn = 1;
int main()
{
string s;
getline(cin, s);
for (int i = 0; i < s.size(); i++)
{
dp[i][i] = 1;
if (i < (s.size() - 1)&&s[i]==s[i+1])
{
dp[i][i + 1] = 1;
maxn = 2;
}
}
for (int L = 3; L <= s.size(); L++)
{
for (int i = 0; i+L-1< s.size(); i++)
{
int j = i + L - 1;
if (s[i] == s[j] && dp[i + 1][j-1] == 1)
{
dp[i][j] = 1;
maxn = L;
}
}
}
printf("%d\n", maxn);
return 0;
}
中心扩展
#include<iostream>
#include<algorithm>
#include<string>
using namespace std;
int main()
{
int maxn = 1;
string s1,s2;
getline(cin, s1);
for (int i = 0; i < s1.size(); i++)
{
s2 += '&';
s2 += s1[i];
}
s2 += '&';
for (int i = 1; i < s2.size(); i++)
{
int step = 1, l, r;
for (l = i - 1, r = i + 1; l >= 0 && r < s2.size(); l--, r++)
{
if (s2[l] != s2[r]) break;
step += 2;
}
maxn = max(maxn, step);
}
printf("%d", maxn/2);
return 0;
}
后记
这道题是一道非常经典的题,对应LeetCode上的1005,方法众多,我只能写出这么几种了。。。。。。。。。
这道题非常值得学习!