牛客网题-计算某字符出现的次数

发布时间 2023-04-09 23:26:48作者: 针眼画师

之前做了一道逆序排单词的题, 今天做这道题原本认为很简单,但是却出问题了.

问题在于输入: 输入是分成两行完成的, 因此第一行结尾会有一个换行符, 他非常关键


当输入的字符数小于1000时, 换行符被储存到数组中, 然后可以直接用scanf()读取换行之后的值, 也就是需要看重复多少次的那个值, 一切都能正常运行.

当输入的字符大于等于1000时,fgets()只能取这1000个字符, 多于的字符和换行符留在那里, 这时候, 如果还是使用scanf(), 那么只会读到输入的第1001个字符, 不一定是什么, 在下面这个例子中,字符正好1000个, 第1001个是换行符, 所以scanf()会读到一个换行符, 结果输出为0; 因此, 需要额外增加一个判断语句, 用以应对不同情况.


运行数据
655b203khDc79w76239SC60Yx5O634244O8oNKw2g5c122dt9M17197FQ9fR0fC8619q00cC156NJQ958ZAH8qe76G024Xvy74ETiO10WgQmOuNx104B9L8Euod682x6hVX941DUalUwb20nyD6IX6IM57Jvypu2mtZ8fpk9Z72AU9g0zob32W7J427VT50P7x40d6QF1067yYMioy6E037e2fTDTse6Z983873849KSB3t93t1wR14717iDi9ybw76h9410q345Z4882zWY3v7C0jD33NlLiF53Hp69067Dzvu1s4Er0G24MhcAHEq151Y339jyfbP6w9j1dX72DEv7L02764f2K7XVf7tWNYGqU5iNlS5RpV619vg7zR96D8jMsO5xN223W97CMuHHWBX806AD732q42h1bwpSb923V3Q73D3g3O0100tk948693d67nxrd7LB6He5O9qG2i9xJ0U1x9054y20039V9uD61HF9eP825JJ79M200X3zH1pW99QeG40kR4275p5P96S3J6mj60z278C1K685As6CX35rcY70qI5810i3rt5WB1C6H74118433Z8wsfE9s2M82q7TN7Q6Zz3047W99g56kLK58NqPfSuhSfEs0W4u1D720A3jqpG7aD0Be3N18395zS037T0Rg47K3O90H5w5660bNW58O8TK3l38xyN7R36kH4l21VYDx3waZK8kf5O3ySWJQdN7eVnf778GIa70Fan34v0owxkg4N5keNbaxh044l67Vimm110i7N8614Xj4667rQd6R67aHlm5z6N51jtbAm22305l9p83Uu6l8pBOaxQL56c5M76SUUKv9538FVD28WT1046sPQ1eHf5e65tk3Q6Lub314FBNv2C4Q12e6oPcX95jC06g8oFj7q7V20ciEO73m00U8v8342H1w86yS298r094x2y8O24e8p6j685D9a539930DQ6s6813uF8D34i6E1x5j2v9
1
牛客网在线编程代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
写出一个程序,接受一个由字母、数字和空格组成的字符串,和一个字符,然后输出输入字符串中该字符的出现次数。(不区分大小写字母)
数据范围: 1≤n≤1000 
*/
// 第一行输入一个由字母、数字和空格组成的字符串,第二行输入一个字符(保证该字符不为空格)。
// 输出输入字符串中含有该字符的个数。(不区分大小写字母)
int main() {
    // 给数组分配内存,存放输入的字符串,接受1000个字符,第1001个用于存放\0
    char* words;
    words = (char*) malloc(sizeof(char) * 1001);
    // 存放字符串长度
    int len;
    // 存放需要查询的字符
    char ans;
    // 初始化字符数组
    *words = 0;
 
    // 接受字符串输入,只进入1000个字符,多了不要
    fgets(words, 1001, stdin);
    // 计算字符串大小
    len = strlen(words) ;
    // 接受需要查询的字符                                  ----------->需要判断结尾是否有换行符
    if (words[999] == '\n' || words[999] == 0) {
        scanf("%c", &ans);
    } else {
        while (getchar() != '\n') {
        }
        scanf("%c", &ans);
    }
 
    // 遍历字符串,如果遇到与给定字符相同的字符,计数器+1
    int m = 0;
    // 因为题目的字符类型不包含换行符,所以len-2
    for (int i = 0; i <= len - 2; i++) {
        // 因为不区分大小写字母,所以要写或
        // 大写字母在65~90,小写字母在97~122 ,用asciis码数字比较也可以,但是有数字输入就会混淆,不如用字母
        if (ans <= 'Z' && ans >= 'A') {
            // 大写字母,则小写字母也可以
            if (words[i] == ans || words[i] == ans + 32) m++;
        } else if (ans <= 'z' && ans >= 'a') {
            // 小写字母,则大写字母也可以
            if (words[i] == ans || words[i] == ans - 32) m++;
        }
        // 其他字符正常比较就好
        else {
            if (words[i] == ans) m++;
        }
    }
    // 输出结果
    printf("%d", m);
 
    // 释放内存
    free(words);
 
    return 0;
}


上面是牛客网的在线编译系统运行的, 使用getchar()效果很好, 能够跳过无用的字符, 找到那个我们需要计数的字符

在本地的DevC++上运行类似的代码, 却出现读取上的错误. 我照旧把数据放到一个文本文件中, 然后读取, 却不能进行下去, 当我使用scanf()时, 需要在终端输入. 使用getchar()时也是一样, 使用fgets()可以读取, 但是却无法正常输出.


刚才我才发现, 使用fgets(), 会把使用的数组强行变成字符串, 我在下面的代码中定义了char ans[1], 他本来应该是一个大小为1的字符数组, 我进行printf("%s",ans);, 输出了字符1, 我进行printf("%c",ans);, 得到了乱码, 我根本没有想到数组大小会变. 我尝试性进行printf("%c",ans[0]);printf("%c",ans[1]);, 前者输出字符1, 后者输出空字符, 我终于意识到字符数组变成了字符串.

但令人不解的是, 我对ans分别使用sizeof()strlen()计算大小, 他们算出的大小竟然是一样的 !

这触及了我知识范围外的内容, 以后水平提高了再解决吧, 记住fgets()的这个特点就是了

image
42是1出现的次数, 上面从上到下的两个1是分别是sizeof()计算和strlen()计算的ans的大小.

我在DevC++写的代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/*
写出一个程序,接受一个由字母、数字和空格组成的字符串,和一个字符,然后输出输入字符串中该字符的出现次数。(不区分大小写字母)
数据范围: 1≤n≤1000 
*/
// 第一行输入一个由字母、数字和空格组成的字符串,第二行输入一个字符(保证该字符不为空格)。
// 输出输入字符串中含有该字符的个数。(不区分大小写字母)
int main() {
	FILE *fp=fopen("HJ2计算某字符出现次数.txt","r");
	// 给数组分配内存,存放输入的字符串,接受1000个字符,第1001个用于存放\0  
    char *words;
    words=(char*) malloc(sizeof(char)*1001);
    // 存放字符串长度
	int len; 
    // 存放需要查询的字符 
    char ans[1];
    // 初始化字符数组 
    *words=0;
    
    // 接受字符串输入,只进入1000个字符,多了不要 
    fgets(words,1001,fp);
    // 测试用,输出字符串
	printf("%s",words); 
    // 接受需要查询的字符
    // ans=getchar();
	// scanf("%c",&ans);
    fgets(ans,2,fp);
    while (ans[0]!='\n') 
	{
		fgets(ans,2,fp);
		printf("%c",ans[0]);
	}
	fgets(ans,2,fp);
	// 测试用,输出需要查询的字符 
	printf("%c\n",ans[0]);
	// 计算字符串大小
	len=strlen(words) ;
	// 测试用,输出字符串大小,这里包含了换行符 
	// printf("\n%d\n",len); 
	// 关闭文件,释放文件占用的内存
	fclose(fp); 
	
	// 遍历字符串,如果遇到与给定字符相同的字符,计数器+1
	int m=0;
	// 因为题目的字符类型不包含换行符,所以len-2 
	for (int i=0;i<=len-2;i++)
	{
		// 因为不区分大小写字母,所以要写或 
		// 大写字母在65~90,小写字母在97~122 ,用asciis码数字比较也可以,但是有数字输入就会混淆,不如用字母
		if (ans[0]<='Z' && ans[0]>='A')
		{	
			// 大写字母,则小写字母也可以 
			if (words[i]==ans[0] || words[i]==ans[0]+32) m++;
		}
		else if (ans<='z' && ans>='a')
		{
			// 小写字母,则大写字母也可以 
			if (words[i]==ans[0] || words[i]==ans[0]-32) m++;
		}
		// 其他字符正常比较就好 
		else
		{
			if (words[i]==ans[0]) m++;
		}
	}
	// 输出结果
	printf("%d",m); 
	
    // 释放内存
	free(words); 
    
    return 0;
}