反向互补子串

本文介绍了第五届在线编程大赛中的一道关于反向互补子串的问题。题目要求求解最长的反向互补子串长度。作者通过分析题目,指出这是一个动态规划(DP)问题,并分享了自己尝试解答但未能找出错误的算法思路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

第五届在线编程大赛月赛指定题目:反向互补子串

题目详情

这是个字符串问题。我们的字符串只包含大写字母。我们定义一个字母和它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求解,需要找到最优子结构,
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值