第373题解析 字母出现次数统计 | 豆包MarsCode AI刷题

118 阅读3分钟

问题核心

我们需要统计字符串中,每个小写字母出现的次数,并找出出现次数 大于等于 kkk 的字母个数。这个问题可以通过构建一个哈希表(即字母 -> 出现次数的映射)高效解决。

代码如下

from collections import Counter

def solution(s, k):
    # 统计每个字母出现的次数
    frequency = Counter(s)
    # 统计至少出现k次的字母个数
    count = sum(1 for char, freq in frequency.items() if freq >= k)
    return count

这是一个比较简单的使用哈希表的例题,借此我们阐述一下哈希表的有关知识。

哈希表是一种高效的数据结构,主要用于 快速查找、插入和删除 数据。它通过键值对(key-value)的形式存储数据,能在平均情况下以 O(1)O(1)O(1) 的时间复杂度完成操作。


1. 哈希表的定义

哈希表是一种通过 哈希函数 将键(Key)映射到一个固定范围内的数组索引上,从而实现高效数据存储和查询的数据结构。

  • 键(Key): 唯一标识数据的值。
  • 值(Value): 与键关联的数据内容。
  • 哈希函数(Hash Function): 用于将键映射为数组索引的函数。

例如,在 Python 中的 dictset 数据类型就是基于哈希表实现的。


2. 哈希表的工作原理

  1. 存储过程:

    • 将键通过哈希函数转化为数组的索引位置。
    • 将键值对存储到对应位置。
  2. 查找过程:

    • 使用相同的哈希函数计算键的索引。
    • 在对应位置直接找到值。

3. 哈希表的优点

  • 查找快速: 哈希表平均情况下查找时间复杂度为 O(1)O(1)O(1)。
  • 插入删除快速: 插入和删除数据同样为 O(1)O(1)O(1)。
  • 动态调整: 哈希表通常会自动扩展以避免存储冲突。

4. 哈希冲突

由于不同的键可能映射到相同的索引位置,哈希表需要解决 冲突(Collision) 问题。

常见的冲突解决方法包括:

  1. 链地址法(Chaining): 在冲突位置存储一个链表,冲突的键值对存储在链表中。
  2. 开放地址法(Open Addressing): 在数组中寻找其他可用的空位存储冲突的键值对。

5. 常见操作

在哈希表中,主要有以下操作:

  1. 插入:

    • 时间复杂度:O(1)O(1)O(1)。
    • 将键值对存入哈希表。
    • 例如:hash_table["key"] = value
  2. 查找:

    • 时间复杂度:O(1)O(1)O(1)。
    • 根据键返回对应的值。
    • 例如:value = hash_table["key"]
  3. 删除:

    • 时间复杂度:O(1)O(1)O(1)。
    • 根据键删除对应的键值对。
    • 例如:del hash_table["key"]

6. 哈希表的优缺点

优点:

  1. 高效: 平均查找、插入和删除时间复杂度为 O(1)O(1)O(1)。
  2. 简单: 易于实现,应用广泛。
  3. 灵活: 支持动态扩展,能够存储任意类型的键和值。

缺点:

  1. 可能浪费空间: 哈希表需要提前分配空间,可能会浪费存储。
  2. 最坏情况较差: 如果哈希函数不好,冲突较多,最坏情况下复杂度为 O(n)O(n)O(n)。
  3. 无法保持顺序: 哈希表中的数据存储无序。

7. 实际应用

哈希表在许多领域中都有广泛应用:

  1. 快速查找:

    • 在 Python 中,dictset 用于高效查找、插入和删除。
    • 实现数据缓存(如 LRU Cache)。
  2. 频次统计:

    • 统计字符出现频次(如字母频率统计问题)。
    • 统计数组中元素的出现次数。
  3. 查重问题:

    • 判断数据是否存在重复值。
    • 寻找一组数据中第一个重复的值。
  4. 集合运算:

    • 计算两个集合的交集、并集、差集。