PAT 1040 Longest Symmetric String[dp][难]
1040 Longest Symmetric String (25)(25 分)
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
题目大意:
//自己写的土鳖方法,以每个字符串为对称中心进行判断。一开始只考虑了对称长度是偶数的情况,没有考虑奇数。得了21分。加上判断奇数的,只得了23分,还是有一个测试点没过去,没找到是什么原因,暂时放一下。
#include <iostream> #include <algorithm> #include <string> #include<stdio.h> using namespace std; int main() { string s=""; char ch; while(ch=getchar()){ if(ch=='\n')break; if(ch==' ')s+=" "; else s+=ch; } int len=s.size(); int ct=0,tp=0; for(int i=1;i<len-1;i++){ for(int j=1;j<=i;j++){ if(i+j>=len)break; if(s[i-j]==s[i+j]) tp++; else break; } if(2*tp+1>ct)ct=2*tp+1; tp=0; } tp=0; for(int i=1;i<len-1;i++){ for(int j=0;j<=i;j++){ if(i+j+1>=len)break; if(s[i-j]==s[i+j+1]) tp++; else break; } if(2*tp>ct)ct=2*tp; tp=0; } cout<<ct; return 0; }
这个代码也是通过判断对阵中心,不过使用了reverse函数, 以前见过的,对string判断对称,使用reverse
通过截取,如果是偶数时,那么对称中心就是中间靠左的那个,(和中位数一样。)
#include <cstdio> #include <iostream> #include <string> #include <algorithm> using namespace std; int main(){ string s; getline(cin, s); int len = 1; for (int i = 0; i < s.size(); i++){ for (int j = 0; j <= min(i, int(s.size())-1-i); j++){ //这个最小值表示向左向右还最多可以截取几个。是需要min来限制的。 string s2 = s.substr(i-j,2*j+1); string s3 = s2; reverse(s2.begin(), s2.end()); if (s2 == s3){ if (s2.size() > len) len = s2.size(); } string s4 = s.substr(i-j, 2*j+2);//这个如果i指向,最后一个,是会和上边重判的。是截取一个。 string s5 = s4; reverse(s4.begin(), s4.end()); if (s4 == s5){ if (s4.size() > len) len = s4.size(); } } } printf("%d\n", len); return 0; }
//下面是大佬的dp版本:https://www.liuchuo.net/archives/2104
#include <iostream> #include<stdio.h> using namespace std; int dp[1010][1010];//dp[i][j]只有0和1取值,表示i和j之间是否是 int main() { string s; getline(cin, s);//直接getline可以读进去字符串里。 int len = s.length(), ans = 1; for(int i = 0; i < len; i++) { dp[i][i] = 1; if(i < len - 1 && s[i] == s[i+1]) { dp[i][i+1] = 1; ans = 2; } } for(int L = 3; L <= len; L++) { for(int i = 0; i + L - 1 < len; i++) {//总长度的限制。 int j = i + L -1; if(s[i] == s[j] && dp[i+1][j-1] == 1) { dp[i][j] = 1; ans = L; } } } printf("%d", ans); return 0; }
//dp数据只有0和1取值,dp[i][j]表示i到j是否是对称的,为了保证状态的转移,使用长度作为循环,因为2很好判断,那么就从L=3开始,i每次都从0开始,那么j就是那个对应的结束,要满足的条件自然是j+L-1<len了。而最终的答案自然是最大的L。还有dp[i+1][j-1]也是神了,这就是坐进右退判断对称的。