出现频率最高的字母

前言

我们已经学习了数组、字符串、链表等数据结构,但是大家有没有发现,如果我们想要找到其中某个元素或者节点,需要从索引为0的位置或者表头开始,逐一进行比较,直到找到相等的位置或者末尾才会结束。

那是否可以避免之前的比较,直接通过要查找的记录直接找到其存储位置呢?

是有的,可以通过“哈希表”来实现,哈希表是根据关键码key的值而直接进行访问的数据结构。

哈希表的作用是快速判断一个元素是否出现在集合里,它的核心思想是在关键码和存储位置之间建立一个确定的对应关系f, 使得每个关键字key对应一个存储位置,而这个对应关系,称之为散列函数(哈希函数)。

其实数组就是一张哈希表,哈希表中关键码就是数组的索引下标,然后通过下标直接访问数组中的元素。

哈希表来解决问题的时候,一般选择以下三种数据结构。

  • 数组

  • set集合

  • map映射

哈希表

关于哈希表的更多介绍,可以移步至代码随想录官方网站查看

哈希表可以将其比喻为一个大抽屉,抽屉里面有很多小格子。每个格子可以用来存放一些东西。

  • 抽屉编号: 抽屉有编号,这个编号就是数据的key,我们通过这个key来找到对应的抽屉。

  • 散列函数: 哈希表使用一种特殊的函数(哈希函数),来决定数据应该放在哪个抽屉里。这个函数将数据的名字key转换成一个数字,然后根据这个数字来选择一个抽屉。

  • 抽屉里的物品: 在每个抽屉里,可以放一些东西,这些东西就是我们要存储的数据。

  • 解决冲突: 有时候不同的key经过散列函数后可能会得到相同的编号,这就是冲突。哈希表有方法来处理这些冲突。

  • 快速查找: 当我们需要找到某个数据时,哈希表可以通过名字key快速地找到对应的抽屉,然后取出里面的数据,这个操作非常快速,就像从抽屉中拿出东西一样。

代码编写

照例先把代码的基础结构书写完整

#include <iostream>
#include <string>
using namespace std;
int main() {
  int n; // 接收n行数据
  string s; // 每行输入的字符串
  while(cin >> n) { // 题目包含多个输入
    while(n--) {
      cin >> s;// 接收输入的字符串
    }
  }
}

数组可以作为简单哈希表来使用,所以我们可以定义一个数组,来记录字符串s当中字符出现的次数。

由于输入的全都是小写字母,小写字母只有26个,那我们定义一个长度为26的数组即可,字符a到字符z的ASCII是26个连续的数值,所以字符a映射为下标0,相应的字符z映射为下标25。

替换文本在遍历 字符串s的时候,只需要将s[i] - 'a'所在的索引做+1 操作即可,并不需要记住字符a的ASCII,只要求出一个相对数值就可以了。 这样就将字符串s中字符出现的次数,统计出来了

// 统计各个字符出现的频率
for (int i = 0; i < s.size(); i++) {
    count[s[i] - 'a']++;
}

经过一轮遍历之后已经完成统计,数组中各位的元素已经是a-z字母的频次了,如果想要找到最大值,还是需要重新遍历一遍,那我们如何记录这个最大值呢?

只需要先初始化最大值,然后逐一比对字符出现的频次和当前最大值的大小,如果当前字符出现的频次大于最大值,则更新最大值为当前字符出现的频次,这样完整遍历一遍后,就能找到出现频次最大的字符。

// 初始化最大值
int flag = 0;
// 定义出现频次最多的字符为result
char result;
// 遍历数组,找到值最大的索引
for (int i = 0; i < 26; i++) {
  // 如果当前位置的数值大于最大值,则更新最大值,更新字符
    if (count[i] > flag) {
      // 更新最大值
        flag = count[i];
      // 更新字符
        result = i + 'a';
    }
}
// 输出结果
cout << result << endl;

完整代码如下:

#include <iostream>
#include <string>
using namespace std;
int main() {
    int n;
    string s;
    while (cin >> n) { // 题目中说包含多组测试数据,所以这里要持续输入
        while (n--) {
            cin >> s; // 输入字符串
            int count[26] = {0};
            // 统计各个字符出现的频率
            for (int i = 0; i < s.size(); i++) {
                count[s[i] - 'a']++;
            }
            int flag = 0;
            char result;
            // 找到出现频率最大的字符
            for (int i = 0; i < 26; i++) {
                if (count[i] > flag) {
                    flag = count[i];
                    result = i + 'a';
                }
            }
            cout << result << endl;
        }
    }
} 

总结

本节内容我们学习到了数组作为哈希表的使用,下节课我们会学习哈希表的另外一种形式set集合

不会做游戏!