字符消除

游戏消除策略与得分优化
时间限制:1000ms
单点时限:1000ms
内存限制:256MB

描述

小Hi最近在玩一个字符消除游戏。给定一个只包含大写字母"ABC"的字符串s,消除过程是如下进行的:


1)如果s包含长度超过1的由相同字母组成的子串,那么这些子串会被同时消除,余下的子串拼成新的字符串。例如"ABCCBCCCAA"中"CC","CCC"和"AA"会被同时消除,余下"AB"和"B"拼成新的字符串"ABB"。

2)上述消除会反复一轮一轮进行,直到新的字符串不包含相邻的相同字符为止。例如”ABCCBCCCAA”经过一轮消除得到"ABB",再经过一轮消除得到"A"


游戏中的每一关小Hi都会面对一个字符串s。在消除开始前小Hi有机会在s中任意位置(第一个字符之前、最后一个字符之后以及相邻两个字符之间)插入任意一个字符('A','B'或者'C'),得到字符串t。t经过一系列消除后,小Hi的得分是消除掉的字符的总数。


请帮助小Hi计算要如何插入字符,才能获得最高得分。


输入

输入第一行是一个整数T(1<=T<=100),代表测试数据的数量。

之后T行每行一个由'A''B''C'组成的字符串s,长度不超过100。


输出

对于每一行输入的字符串,输出小Hi最高能得到的分数。


提示

第一组数据:在"ABCBCCCAA"的第2个字符后插入'C'得到"ABCCBCCCAA",消除后得到"A",总共消除9个字符(包括插入的'C')。

第二组数据:"AAA"插入'A'得到"AAAA",消除后得到"",总共消除4个字符。

第三组数据:无论是插入字符后得到"AABC","ABBC"还是"ABCC"都最多消除2个字符。


样例输入
3
ABCBCCCAA
AAA
ABC
样例输出
9
4

2

#include<stdio.h>
#include<string.h>
char str1[110],str2[110],str3[110];
int cal(char str[])
{
	int len=strlen(str);
	int n=len,flag=1,i,j,k;
	while(flag&&n>0)
	{
		for(j=0,i=0;i+1<n;)
		{
			if(str[i]!=str[i+1])
				str3[j++]=str[i++];
			else 
			{
				while(str[i]==str[i+1]) i++;
				i++;
			}
		}
		if(str[i]!='\n')str3[j++]=str[i++];
		str3[j]=0;
		if(strcmp(str3,str)==0) flag=0;
		else strcpy(str,str3);
		n=strlen(str3);
	}
	return len-n;
}
int main()
{
	int t,i,j,len;
	scanf("%d",&t);
	while(t--)
	{
		int ans=-1;
		scanf("%s",str1);
		len=strlen(str1)+1;
		for(i=len-1;i>0;i--)
		{
			for(int k=0;k<3;k++)
			{
				for(j=len-1;j>i;j--)
					str2[j]=str1[j-1];
				str2[i]='A'+k;
				for(j=i-1;j>=0;j--)
					str2[j]=str1[j];
				str2[len]=0;
				ans=max(ans,cal(str2));
			}
		}
		printf("%d\n",ans);
	}
	return 0;
}


<think>我们参考了用户提供的多个引用,这些引用展示了C语言中处理字符串的几种常见操作: 1. 引用[1]展示了字符串以'\0'结束的特性,并说明puts函数会将'\0'转换为'\n'输出。 2. 引用[2]展示了一个去除字符串开头和结尾空白字符的函数。 3. 引用[3]展示了一个去除字符串中所有空格的方法(但该方法效率不高且有重复检测的问题)。 4. 引用[4]展示了去除字符串尾部换符的方法。 用户的问题:在C语言中消除字符的方法。 根据引用,我们可以总结几种常见的消除字符操作: - 消除字符串开头和结尾的空白字符(包括空格、制表符、换符等) - 消除字符串中所有空格(或其他特定字符) - 消除字符串尾部的特定字符(如换符) 注意:在C语言中,字符串以'\0'作为结束符,因此我们不能直接“删除”字符,而是通过移动字符和调整结束符的位置来实现。 下面我们将分别介绍几种常见的消除字符的方法: ### 1. 消除字符串开头和结尾的空白字符 引用[2]提供了一个标准的去除字符串两端空白的方法,使用`isspace`函数判断空白字符。 ```c #include <ctype.h> #include <string.h> char *trim(char *str) { char *end; // 去掉开头的空白字符 while (isspace((unsigned char)*str)) str++; if (*str == '\0') // 如果字符串全是空白,则直接返回 return str; // 去掉结尾的空白字符 end = str + strlen(str) - 1; while (end > str && isspace((unsigned char)*end)) end--; // 写入新的结束符 end[1] = '\0'; return str; } ``` ### 2. 消除字符串中所有空格(或其他指定字符) 引用[3]提供了一个去除字符串中所有空格的方法,但该方法效率较低(每次遇到空格就将其后的非空格字符前移,并且会重复检测空格)。我们可以使用双指针法更高效地移除所有空格。 ```c void remove_all_spaces(char *str) { if (str == NULL) return; // 使用两个指针:一个用于遍历,一个用于指向非空格字符的写入位置 char *p = str; char *q = str; while (*p != '\0') { if (*p != ' ') { // 如果不是空格,则复制 *q = *p; q++; } p++; } *q = '\0'; // 设置新的结束符 } ``` 如果要移除其他指定字符,只需将条件`*p != ' '`改为`*p != 指定字符`即可。 ### 3. 消除字符串尾部的换符(或其他指定字符) 引用[4]展示了去除字符串尾部换符的方法。我们可以扩展为去除尾部任意指定字符。 ```c void remove_trailing_char(char *str, char c) { if (str == NULL) return; size_t len = strlen(str); // 从字符串末尾开始向前检查 while (len > 0 && str[len-1] == c) { len--; // 相当于将结束符前移 str[len] = '\0'; } } ``` 注意:这种方法只能去除尾部连续的指定字符。例如,去除尾部换符可以调用`remove_trailing_char(str, '\n')`。 ### 总结 - 消除两端空白:使用`trim`函数(引用[2])。 - 消除所有空格:使用双指针法(改进引用[3]的方法)。 - 消除尾部指定字符:使用`remove_trailing_char`函数(扩展引用[4])。 另外,注意字符串操作的安全性,确保操作不会越界。 §§相关问题§§ 1. 如何去除C语言字符串中指定的多个字符? 2. 在C语言中,如何高效地删除字符串中间的空格? 3. 字符串处理函数中如何避免缓冲区溢出? </think>在C语言中"消除字符"通常指从字符串中去除特定字符(如空格、换符等)。根据引用内容,以下是几种常见方法和实现原理: ### 一、消除字符串首尾空白字符 引用[2]展示了标准实现: ```c #include <ctype.h> #include <string.h> char *trim(char *str) { char *end; // 去除开头空白 while (isspace((unsigned char)*str)) str++; if (*str == '\0') return str; // 全空白则直接返回 // 去除结尾空白 end = str + strlen(str) - 1; while (end > str && isspace((unsigned char)*end)) end--; *(end + 1) = '\0'; // 设置新结束符 return str; } ``` 关键点: 1. `isspace()`检测空白字符(空格、制表符、换等) 2. 修改结束符`'\0'`位置实现"截断" 3. 时间复杂度$O(n)$ ### 二、消除字符串中间空格 引用[3]展示了移位覆盖法: ```c void remove_spaces(char *p) { char *q; while (*p) { if (*p == ' ') { q = p; while (*q) { // 移位覆盖空格 *q = *(q+1); q++; } } else p++; } } ``` 缺点:效率较低($O(n^2)$时间复杂度) **优化方案(双指针法)**: ```c void remove_all_spaces(char *str) { char *dst = str; while (*str) { if (*str != ' ') *dst++ = *str; str++; } *dst = '\0'; // 重置结束符 } ``` ### 三、消除尾部特定字符 引用[4]展示换符移除: ```c void remove_trailing_newline(char *str) { size_t len = strlen(str); if (len > 0 && str[len-1] == '\n') { str[len-1] = '\0'; // 直接替换结束符 } } ``` 通用化方案: ```c void remove_trailing_char(char *str, char c) { size_t len = strlen(str); while (len > 0 && str[len-1] == c) { str[--len] = '\0'; } } ``` ### 四、核心原理总结 1. **字符串本质**:以`'\0'`结尾的字符数组(引用[1]) 2. **消除方法**: - 移动有效字符覆盖目标字符(引用[3]) - 修改`'\0'`位置截断字符串(引用[2][4]) 3. **安全注意**: - 避免缓冲区溢出(确保目标地址可写) - 检查空指针(如`if(!str) return;`)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值