哈希算法题目:哈希表在解决“最大频率栈”问题中的应用
字数 1759 2025-12-06 02:10:25
哈希算法题目:哈希表在解决“最大频率栈”问题中的应用
题目描述
你需要实现一个“频率栈”数据结构,支持以下操作:
push(val):将整数val推入栈中。pop():弹出并返回栈中出现频率最高的元素。如果频率最高的元素不唯一,则返回最近被推入的那个元素(即满足最高频率的、最靠近栈顶的元素)。
举例
freqStack = FreqStack()
freqStack.push(5) # 栈: [5]
freqStack.push(7) # 栈: [5,7]
freqStack.push(5) # 栈: [5,7,5]
freqStack.push(7) # 栈: [5,7,5,7]
freqStack.push(4) # 栈: [5,7,5,7,4]
freqStack.push(5) # 栈: [5,7,5,7,4,5]
freqStack.pop() # 返回 5,因为 5 出现 3 次(最高频),栈: [5,7,5,7,4]
freqStack.pop() # 返回 7,因为 5 和 7 都出现 2 次,但 7 是最近推入的,栈: [5,7,5,4]
freqStack.pop() # 返回 5,栈: [5,7,4]
freqStack.pop() # 返回 4,栈: [5,7]
逐步解题过程
第一步:理解需求与难点
- 需要快速获取当前“频率最高的元素”,若有多个相同最高频率的元素,需知道它们被推入的顺序,以便弹出“最近”的那个。
- 不能简单用单个最大堆,因为“最近推入”的顺序在弹出后会动态变化。
第二步:核心数据结构设计
使用三个关键部分:
-
频率表(
freq字典)- 键:元素值
val。 - 值:该元素当前的出现频率。
- 用途:快速知道一个元素的当前频率。
- 键:元素值
-
分组栈(
group字典)- 键:频率值(整数)。
- 值:一个列表(栈),按推入顺序存放所有达到该频率的元素。
- 举例:当元素
5第 1 次出现时,它会被放入group[1]的栈中;当它第 2 次出现时,又会被放入group[2]的栈中。 - 用途:对同一频率的所有元素,其入栈顺序自然被保留,栈顶就是该频率下“最近推入”的元素。
-
当前最大频率(
maxFreq)- 一个整数,记录全局最高频率,确保
pop()时能快速定位到group[maxFreq]栈。
- 一个整数,记录全局最高频率,确保
第三步:操作步骤详解
push(val) 操作
- 更新
freq[val] += 1(若val不存在则初始化为 0 再加 1)。得到新频率f。 - 将
val推入group[f]对应的栈中(若group[f]不存在则创建一个空栈)。 - 更新
maxFreq = max(maxFreq, f)。
为什么放入
group[f]而不是group[f-1]?
因为f是当前该元素出现的总次数,而group[f]存储的是“在达到频率 f 的那一刻的元素”。这样,当需要弹出频率为 f 的元素时,直接从group[f]栈顶取即可。
pop() 操作
- 从
group[maxFreq]栈中弹出栈顶元素x。 - 将
freq[x] -= 1(因为该元素被移出了一个,所以频率减少 1)。 - 如果
group[maxFreq]栈为空,则maxFreq -= 1。 - 返回
x。
第四步:手动模拟示例
初始化:freq = {}, group = {}, maxFreq = 0。
-
push(5)freq[5] = 1group[1] = [5]maxFreq = 1
-
push(7)freq[7] = 1group[1] = [5, 7]maxFreq = 1
-
push(5)freq[5] = 2group[2] = [5]maxFreq = 2
-
push(7)freq[7] = 2group[2] = [5, 7]maxFreq = 2
-
push(4)freq[4] = 1group[1] = [5, 7, 4]maxFreq = 2
-
push(5)freq[5] = 3group[3] = [5]maxFreq = 3
-
pop()- 从
group[3]弹出5,group[3]变空。 freq[5] = 2maxFreq降为 2(因为group[3]空)。- 返回
5。
- 从
-
pop()- 从
group[2]弹出栈顶7。 freq[7] = 1group[2]还剩[5],不空,所以maxFreq仍为 2。- 返回
7。
- 从
… 以此类推,符合预期结果。
第五步:复杂度分析
- 时间复杂度:
push和pop都是 O(1)。 - 空间复杂度:O(N),N 为推入元素的总次数。
第六步:关键点总结
- 利用“分组栈”将相同频率的元素按推入顺序组织,栈顶即最近推入的元素。
- 维护
maxFreq避免每次弹出时扫描所有频率。 - 该设计本质上是哈希表(字典)的嵌套使用,外层键是频率,内层是栈,实现频率与顺序的分离管理。