题目
字母出现频率是指26英文个字母在文章中出现的频率。根据统计,在英语中最常出现的字母是e,大约占12~13%,出现最少的字母是z,不到0.1% ,如下图所示(统计结果来自wiki百科)
字母出现频率的统计结果可用于破解密码,例如基于字母移位替换的ROTn密码(又称为恺撒密码);在很多压缩工具中,也要统计字母(或字符、单词)出现的频率,以便用更少的二进制位存储出现频率较高的字母(字符、单词),从而减少数据占用的存储空间
输入
输入一段文章,字数少于10000,统计文章中字母A-Z出现的频率(不区分大小写,忽略非字母的符号:数字、标点、换行...)
输出
统计结果按百分数显示,保留两位小数
样例
输入
Introduction to The Junior College of Zhejiang Wanli University
On Huilong Campus, in order to cater to and meet the particular requirements of freshmen, the university implements independent management and places emphasis on fundamental teaching of foreign languages and computer skills.
The course credits, flexible teaching, tutorial system and teaching according to their aptitude, hence student-oriented management system is realized.
输出
A: 7.26% B: 0.27% C: 4.03% D: 4.03% E:13.71% F: 1.88% G: 3.23% H: 3.49% I: 8.06% J: 0.54% K: 0.27% L: 4.03% M: 4.03% N: 9.68% O: 5.65% P: 2.15% Q: 0.27% R: 5.65% S: 5.38% T: 9.68% U: 4.03% V: 0.54% W: 0.27% X: 0.27% Y: 1.08% Z: 0.54%
思路
来自我们学校OJ的一个题目,看似简单实则有坑,为了通过这题我也是花了不少的时间。
总体的思路就是,用一个长度为26数组letters记录下每一个字母的数量最后按格式输出。输入时将字符依次存入字符串变量text中,存放前对其判断大小写,将其统一转换成小写并通过ASCII码的计算将字符转换成索引值,从而给数组letters对应位置上的元素加一,然后给统计总字母个数的变量total加一。
避坑
第一坑:输出的时候所有的百分数都是右侧对齐的,由于是保留了两位小数,所以百分数长度一定不超过5,而百分号不能直接输出,需要转义,所以输出的时候采用"%c:%5.2f%%\n"的方式格式输出。
第二坑:计算百分比的时候分母是字母总个数total,分子是当前字母的出现个数,两者都是int类型,不能计算出小数,所以要给任意一项乘1.0让其转成实型。还有要特别注意的是需要分类讨论分母为0的情况!!
第三坑:输入的时候要用scanf进行输入!由于本人使用了gets函数导致一直过不了这题,gets函数已经在C11标准中被废弃,因为它不会检查输入的长度,无法防止缓冲区溢出,所以在实际应用中不推荐使用。而scanf函数相对于gets函数来说更加安全,因为它逐字符读取,不会一次性读取整行文本。此外,尝试了用fgets(text, sizeof(text), stdin);的输入方式也是过不了这题的。
代码
#include <stdio.h>
#include <ctype.h>
int main()
{char text[10000];int letters[26] = {0}, total = 0, i = 0;while (scanf("%c", &text[i]) != EOF){if (isalpha(text[i])){int index = tolower(text[i]) - 'a';letters[index]++;total++;}i++;}if (total == 0){for (int i = 0; i < 26; i++)printf("%c: 0.00%%\n", 'A' + i);}else{for (int i = 0; i < 26; i++)printf("%c:%5.2f%%\n", 'A' + i, 1.0 * letters[i] / total * 100.0);}return 0;
}