第五届在线编程大赛月赛指定题目:反向互补子串
题目详情
这是个字符串问题。我们的字符串只包含大写字母。我们定义一个字母和它13位以后的字母互补。即A与N互补,B与O互补,C与P互补……,我们需要找一个字符串的两个不重叠的子串,其中一个和另外一个的翻转全互补。另外,因为我们的问题来自生物学,所以我们允许这两个字符串的一个可以删掉两个字符(注意:仅允许一个字符串删掉任意位置的两个字符,另外一个必须全部互补上)。我们的目的是求最长的反向互补子串的长度。输入格式:
多组数据,每组数据一行,有一个字符串。每个字符串长度不超过2000,只有大写英文字母组成。
输出格式:
每组数据输出一行包含一个整数,表示最长的反向互补子串长度。
输入样例
ABCD
ABCDQOPN
ABON
输出样例:
0
2
2
解释:
第一个样例,没有互补的子串。
第二个样例,AB和NO互补,所以反向互补子串的时候我们可以选择NPO,删掉一个P即可。
第三个样例,AB与ON反向互补。
题目分析,该题是DP问题,刚刚接触该问题时,找不到解题点,故而给出了下面的解答,解题错误,但是至今还是没有找到错在哪里,错误的算法如下:
//反向互补子串
#include <stdio.h>
#include <string.h>
//返回从当前参数i开始的字符串中反向互补子串的长度
//len是字符串str的长度
int complementary(const int i,const char *str,const int len);
//判断str[i],str[j]是否互补
//互补返回1,否则返回0
int equal(const char *str,int i,int j);
int main()
{
char str[2001];
memset(str,'\0',sizeof(str));
while(scanf("%s",str)!=EOF)
{
int i=0,len=0,j=0,k=0;
while(str[len]!='\0') ++len;
printf("strLen=%d\n",len);
int maxLen=0;
for(i=0,j=len-1;i<j;++i,--j){
int curLen=complementary(i,str,len);
printf("curLen=%d\n",curLen);
if(maxLen<curLen) maxLen=curLen;
}
printf("answer=%d\n",maxLen);
//str初始化为空串
memset(str,'\0',sizeof(str));
}
return 0;
}
int complementary(const int start,const char *str,const int len)
{
int middle=len/2;
int end=len-1;
//寻找等于str[start]的str[j]
printf("判断equal函数是否满足需要:%d\n",equal(str,start,end)?1:0);
while(end>=middle&&(!equal(str,start,end))) --end;
//调试代码
printf("middle=%d\tend=%d\n",middle,end);
//不存在满足条件的子串,返回长度0
if(end<middle) return 0;
int i=0,j=0;
//左边、右边顺序串的长度
int leftLen=0,rightLen=0;
//从start开始的当前互补子串的长度
//删除掉的字符个数
int del=0;
//先得到左边的长度
for(i=start,j=end;i<middle&&del<2;){
if(equal(str,i,j)){
++i,--j;
}else{
del++;
--j;
}
}
//leftLen=del<2?i-start+1:i-start;
leftLen=i-start;
//调试用的
printf("start=%d\nleftLen=%d\t",start,leftLen);
//从右边开始字符串的长度
del=0;
for(i=start,j=end;i<middle&&del<2;){
if(equal(str,i,j)){
++i,--j;
}else{
del++;
++i;
}
}
//rightLen=i<middle?end-j+1:end-j;
rightLen=end-j;
printf("rightLen=%d\n",rightLen);
return leftLen>rightLen?leftLen:rightLen;
}
int equal(const char *str,int i,int j)
{
return ((str[i]-str[j]==13)||(str[j]-str[i]==13));
}
利用DP求解,需要找到最优子结构,