这是题目。初见觉得还好,谁知道越分析越操蛋暗含深意。仔细看,假设我们通过遍历s1删除了两个显性的cat,哎,剩下的是什么
Tom is a male cat
咋样,牛逼不。说明这题肯定会出现删除一次不够的样例sample。
假设我们熟知C语言中#include<string.h>
中的strcat
,strstr
,strcpy
等函数,那么这题可以比较简洁。
首先大致介绍一下函数(C语言str函数系列-CSDN博客)这里有str函数的函数原型,如果想深入了解可以看看
strcat(s1,s2)
是直接把s2接s1后面
strstr(s1,s2)
可以返回一个char*的指针,指向s1字符串中第一次出现s2字符串的位置
strcpy(s1,s2)
可以将s2拷贝到s1里。
#include<stdio.h>
#include<string.h>
int main()
{
char s1[81] = { 0 };//注意,至少要81,因为题目说最大字符串为80,给'\0'预留一个位置,所以要81
char s2[81] = { 0 };
gets(s1);//用get函数读取字符串有两个好处,首先,输入不会被空格打断(scanf只读取空格之前的东西,空格之后的会被放在缓冲区)符合要求
gets(s2);//其次,与fget相比,不会读到标志着字符串输入完毕的回车,在本例中,我们不需要回车.plus,vs编译器里只能用gets_s
int len2 = strlen(s2);//取s2长度
char* p = strstr(s1, s2);//用指针p存放s1中s2出现的位置,如果没有会接收到null空指针
while ((p=strstr(s1,s2)) != NULL)//条件判断,因为有可能需要多次删除
{
char t[80];//用来储存s1中第一次出现s2之后的所有字符串
strcpy(t,p+len2);//这里p+len2是因为char是一个字节的数据,所以在对地址操作时+len2就可以跳过len2个字符,即跳过s2
//因为数组和指针本质都是地址,所以这里直接把p+len2传入,函数会从该位置开始读,直到读到'\0'为止,这里的'\0’是原来s1末尾的
*p = '\0';//把p位置的字符改成'\0',对于s1来说等于直接舍去了p位置后面的字符
strcat(s1, t);//直接接上,没啥好说的
}
puts(s1);//用puts函数,或者用printf("%s",s1),反正别用for加上printf("%1c",s1[i]),我当年就是这么写的,现在看看真的蠢
}
但是,假设我是个摆子,不知道string.h函数库里的函数,有没有办法硬刚呢。
有是有,但是不知道为啥我写的东西在pta平台的gcc编译器不认,实际上这段代码是没问题的
#include<stdio.h>
#include <string.h>
bool missle(char s1[], char s2[],int& i,int& len1,int& len2,int& flag)
{//这里的missle函数用于判断在s1的第i个字符是否后面接着s2的剩余部分
//由于程序运行到这有一个itr变量从i的位置向前飞,每飞一个字符就检查,像一个导弹一样哈哈哈
int itr = 0;
for (; itr < len2; itr++)
{
if (s1[i + itr] == s2[itr])//用itr往后遍历判断是否是要删除的字符
continue;
else
return false;
}
flag = 1;//如果s1中真的还存在s2,把flag设为1,让whlie循环在跑一次
i = i + itr - 1;直接把i放到s2后面的第一个字符,方便使用s1[n]=s1[i]
return true;
}
int main()
{
char s1[81] = { 0 };//还是一样,一定要81!!
char s2[81] = { 0 };
gets_s(s1);
gets_s(s2);
int flag = 1;//用于检查是否删完了
while (flag)
{
int n = 0;
flag = 0;//这里设为0保证等会的flag如果不受到改变,
//就不会有下一个while循环
int len2 = strlen(s2);
int len1 = strlen(s1);
int i = 0;
for (; i < len1 - len2 + 1; i++)
{
if (missle(s1,s2,i,len1,len2,flag))
continue;//如果是要删除的字符串s2,
//利用循环本身的i++让i继续往后检查有没有可以用于替换s1[n]
的字符
else
{
s1[n] = s1[i];如果i位置不是要删除的字符,把i位置的字符向前移
n++;//只有在i位置的字符前移了才有必要n++
}
}
for (; i < len1; i++)
//在i>=len1-len2之后,s1剩余长度小于s2,没有必要继续检查是否出现s2
{
s1[n] = s1[i];
n++;
}
s1[n] = '\0';
}
printf("%s",s1);
}
这里用到了我搜的一种方法(C语言经典例32-删除字符串中指定的字符_c语言删除字符串中的指定字符,字符串和要删除-CSDN博客),他的方法是针对字符串中删除单个字符串的,很巧妙很值得学习和借鉴,我引用过来之后加了一个missle函数把判断单个字符是否一样变成了判断后面一大串字符是否一样。
害,PTA害人不浅呐,这道题我折腾了快有十个小时,到现在才算是比较明白了,大家如果看的半懂不懂可以先了解str函数,然后试着自己写一次,至少先把第一种的简单的方法写出来,然后在慢慢理解第二种方法。
就算看懂了也要自己在写一遍,这种东西很经常眼睛:我懂了,脑子:好像吧,手:你说啥?