ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

LeetCode 895 最大频率栈(Maximum Frequency Stack)全解:从暴力扫描到 O(1) 双哈希表设计

LeetCode 895 最大频率栈(Maximum Frequency Stack)全解:从暴力扫描到 O(1) 双哈希表设计 LeetCode 895 最大频率栈Maximum Frequency Stack全解从暴力扫描到 O(1) 双哈希表设计【免费下载链接】leetcodeLeetcode solutions项目地址: https://gitcode.com/GitHub_Trending/leetcode1/leetcode本文基于本仓库 maximum-frequency-stack.md 详解文档展开结合仓库内多语言源码Python、Java、C、TypeScript 等进行源码级印证。读完本文你将掌握「最大频率栈」这一经典数据结构设计题的完整解题链路先写出正确但低效的暴力解法再依次升级到基于最大堆的 O(log n) 解法最终实现 push / pop 均摊 O(1) 的「栈的栈」双哈希表设计并理解频率计数、最近插入次序、栈空回退等关键细节的底层原理。问题定义与接口约定Maximum Frequency StackLeetCode 895要求设计一个支持如下两种操作的自定义栈FreqStackpush(val)将一个整数val压入栈中。pop()移除并返回出现频率最高的元素若存在多个频率相同的元素则返回其中**最靠近栈顶最近被压入**的那个。换句话说它并不是严格意义上的 LIFO 栈而是按照「频率优先、同频次按最近插入优先」的规则出栈。这也是它与普通栈、优先队列、LRU 等结构最本质的区别同一个元素被压入多次后会同时存在于多个频率层级中。本仓库对应源码位于0895-maximum-frequency-stack.*系列文件本文以下全部算法均与该系列实现保持一致。前置知识栈Stack维护元素按频率层级分组的核心数据结构提供后进先出语义以表达「最近插入优先」。哈希表Hash Map用于记录元素频率cnt以及把元素按频率分组stacks。堆 / 优先队列Heap / Priority Queue解法二使用最大堆快速取出「频率最高、插入次序最新」的元素。数据结构设计理解如何组合多个数据结构把两种操作同时优化到常数或对数复杂度。解法一暴力法单栈 反向扫描思路最直观的做法维护一个普通栈stack保存所有压入的元素另用哈希表cnt记录每个元素当前出现的次数。pop时先遍历cnt找出全局最大频率maxCnt再从栈顶向栈底反向扫描找到第一个频率等于maxCnt的元素它必然是「同频次中最近压入」的那个将其移除并返回。该做法正确性没有问题但每次pop都要扫描整个栈在大数据量下会超时。算法步骤初始化哈希表cnt记录频率列表stack保存已压入的元素。push(val)把val追加到栈尾并在cnt中将其计数加一。pop()遍历cnt求出最大频率maxCnt从栈尾向前找到第一个cnt[stack[i]] maxCnt的元素移除它、将其计数减一并返回。多语言实现class FreqStack: def __init__(self): self.cnt defaultdict(int) self.stack [] def push(self, val: int) - None: self.stack.append(val) self.cnt[val] 1 def pop(self) - int: maxCnt max(self.cnt.values()) i len(self.stack) - 1 while self.cnt[self.stack[i]] ! maxCnt: i - 1 self.cnt[self.stack[i]] - 1 return self.stack.pop(i)public class FreqStack { private MapInteger, Integer cnt; private ListInteger stack; public FreqStack() { cnt new HashMap(); stack new ArrayList(); } public void push(int val) { stack.add(val); cnt.put(val, cnt.getOrDefault(val, 0) 1); } public int pop() { int maxCnt Collections.max(cnt.values()); int i stack.size() - 1; while (cnt.get(stack.get(i)) ! maxCnt) { i--; } int val stack.remove(i); cnt.put(val, cnt.get(val) - 1); return val; } }class FreqStack { private: unordered_mapint, int cnt; vectorint stack; public: FreqStack() {} void push(int val) { stack.push_back(val); cnt[val]; } int pop() { int maxCnt 0; for (auto [_, frequency] : cnt) { maxCnt max(maxCnt, frequency); } int i stack.size() - 1; while (cnt[stack[i]] ! maxCnt) { i--; } int val stack[i]; stack.erase(stack.begin() i); cnt[val]--; return val; } };class FreqStack { constructor() { this.cnt new Map(); this.stack []; } /** * param {number} val * return {void} */ push(val) { this.stack.push(val); this.cnt.set(val, (this.cnt.get(val) || 0) 1); } /** * return {number} */ pop() { const maxCnt Math.max(...this.cnt.values()); let i this.stack.length - 1; while (this.cnt.get(this.stack[i]) ! maxCnt) { i--; } const val this.stack.splice(i, 1)[0]; this.cnt.set(val, this.cnt.get(val) - 1); return val; } }type FreqStack struct { cnt map[int]int stack []int } func Constructor() FreqStack { return FreqStack{ cnt: make(map[int]int), stack: []int{}, } } func (this *FreqStack) Push(val int) { this.stack append(this.stack, val) this.cnt[val] } func (this *FreqStack) Pop() int { maxCnt : 0 for _, freq : range this.cnt { if freq maxCnt { maxCnt freq } } for i : len(this.stack) - 1; i 0; i-- { val : this.stack[i] if this.cnt[val] maxCnt { this.cnt[val]-- this.stack append(this.stack[:i], this.stack[i1:]...) return val } } return -1 }struct FreqStack { cnt: HashMapi32, i32, stack: Veci32, } impl FreqStack { fn new() - Self { FreqStack { cnt: HashMap::new(), stack: Vec::new(), } } fn push(mut self, val: i32) { self.stack.push(val); *self.cnt.entry(val).or_insert(0) 1; } fn pop(mut self) - i32 { let max_cnt *self.cnt.values().max().unwrap_or(0); for i in (0..self.stack.len()).rev() { let val self.stack[i]; if self.cnt[val] max_cnt { *self.cnt.get_mut(val).unwrap() - 1; self.stack.remove(i); return val; } } -1 } }C#、Kotlin、Swift 版本见 maximum-frequency-stack.md 原文思路完全一致。时间复杂度与空间复杂度时间复杂度push为 O(1)pop为 O(n)其中 n 为栈中元素个数求最大值 O(n) 反向扫描 O(n)。空间复杂度O(n)。n 为栈中元素总数。该方案在大规模输入下会超时仅作为理解题意的起点。解法二最大堆Heap思路暴力法的瓶颈在于每次pop都要线性求最大频率并扫描栈。最大堆可以把「下一个该弹出的元素」直接暴露在堆顶。每个堆条目保存三元组频率freq、插入次序index、值val。堆按如下优先级组织频率大的优先最大堆语义频率相同时插入次序大的优先越晚压入越先弹出。这样堆顶永远是正确的下一个出栈元素push与pop都只需 O(log n) 的堆操作。算法步骤初始化最大堆、频率哈希表cnt以及从 0 开始的全局计数器index。push(val)cnt[val]加一然后把(freq, index, val)三元组压入堆index自增。Python 中利用负数取反实现最大堆(-cnt[val], -index, val)。pop()直接弹出堆顶三元组将该值的频率减一返回其值。多语言实现class FreqStack: def __init__(self): self.heap [] self.cnt defaultdict(int) self.index 0 def push(self, val: int) - None: self.cnt[val] 1 heapq.heappush(self.heap, (-self.cnt[val], -self.index, val)) self.index 1 def pop(self) - int: _, _, val heapq.heappop(self.heap) self.cnt[val] - 1 return valpublic class FreqStack { private PriorityQueueint[] heap; private MapInteger, Integer cnt; private int index; public FreqStack() { heap new PriorityQueue((a, b) - a[0] ! b[0] ? Integer.compare(b[0], a[0]) : Integer.compare(b[1], a[1]) ); cnt new HashMap(); index 0; } public void push(int val) { cnt.put(val, cnt.getOrDefault(val, 0) 1); heap.offer(new int[]{cnt.get(val), index, val}); } public int pop() { int[] top heap.poll(); int val top[2]; cnt.put(val, cnt.get(val) - 1); return val; } }class FreqStack { private: priority_queuevectorint heap; // {frequency, index, value} unordered_mapint, int cnt; int index; public: FreqStack() : index(0) {} void push(int val) { cnt[val]; heap.push({cnt[val], index, val}); } int pop() { auto top heap.top(); heap.pop(); int val top[2]; cnt[val]--; return val; } };class FreqStack { constructor() { this.heap new MaxPriorityQueue({ priority: (element) element[0] * 100000 element[1], }); this.cnt new Map(); this.index 0; } /** * param {number} val * return {void} */ push(val) { this.cnt.set(val, (this.cnt.get(val) || 0) 1); this.heap.enqueue([this.cnt.get(val), this.index, val]); } /** * return {number} */ pop() { const [, , val] this.heap.dequeue().element; this.cnt.set(val, this.cnt.get(val) - 1); return val; } }type Entry struct { freq int index int val int } type MaxHeap []Entry func (h MaxHeap) Len() int { return len(h) } func (h MaxHeap) Less(i, j int) bool { if h[i].freq ! h[j].freq { return h[i].freq h[j].freq } return h[i].index h[j].index } func (h MaxHeap) Swap(i, j int) { h[i], h[j] h[j], h[i] } func (h *MaxHeap) Push(x interface{}) { *h append(*h, x.(Entry)) } func (h *MaxHeap) Pop() interface{} { old : *h n : len(old) x : old[n-1] *h old[:n-1] return x } type FreqStack struct { cnt map[int]int h *MaxHeap index int } func Constructor() FreqStack { h : MaxHeap{} heap.Init(h) return FreqStack{cnt: make(map[int]int), h: h, index: 0} } func (this *FreqStack) Push(val int) { this.cnt[val] heap.Push(this.h, Entry{this.cnt[val], this.index, val}) this.index } func (this *FreqStack) Pop() int { entry : heap.Pop(this.h).(Entry) this.cnt[entry.val]-- return entry.val }struct FreqStack { heap: BinaryHeap(i32, i32, i32), cnt: HashMapi32, i32, index: i32, } impl FreqStack { fn new() - Self { FreqStack { heap: BinaryHeap::new(), cnt: HashMap::new(), index: 0, } } fn push(mut self, val: i32) { *self.cnt.entry(val).or_insert(0) 1; self.heap.push((self.cnt[val], self.index, val)); self.index 1; } fn pop(mut self) - i32 { let (_, _, val) self.heap.pop().unwrap(); *self.cnt.get_mut(val).unwrap() - 1; val } }其中 Kotlin 使用PriorityQueueIntArray并自定义比较器Swift 使用元组数组[(freq, index, val)]并在 push 时排序C# 通过IComparableEntry自定义优先规则完整实现同样见 maximum-frequency-stack.md。时间复杂度与空间复杂度时间复杂度push与pop均为 O(log n)堆的插入与删除。空间复杂度O(n)。n 为栈中元素总数。相比暴力法已大幅提升但仍有对数因子注意堆中可能残留「过期条目」详见文末常见陷阱。解法三栈的栈哈希表实现推荐思路关键洞察按频率层级分组。元素第一次被压入时进入频率为 1 的栈再次被压入时除了保留在频率 1 的栈中还会进入频率 2 的栈……以此类推。由于每个元素在多个频率层级同时存在最高频率层级的栈顶永远就是「当前频率最高且最近压入」的元素。因此pop只需要从stacks[maxCnt]的栈顶弹出一个元素若该层级栈弹空maxCnt减一天然回退到下一个最高频率层级。这种设计让push与pop都达到O(1)。算法步骤初始化频率哈希表cnt、哈希表stackskey 为频率value 为该频率层级的栈、当前最大频率变量maxCnt。push(val)cnt[val]加一得到valCnt若valCnt maxCnt更新maxCnt并为该新频率创建空栈把val压入stacks[valCnt]。pop()从stacks[maxCnt]弹出栈顶元素rescnt[res]减一若stacks[maxCnt]已空则maxCnt减一返回res。多语言实现class FreqStack: def __init__(self): self.cnt {} self.maxCnt 0 self.stacks {} def push(self, val: int) - None: valCnt 1 self.cnt.get(val, 0) self.cnt[val] valCnt if valCnt self.maxCnt: self.maxCnt valCnt self.stacks[valCnt] [] self.stacks[valCnt].append(val) def pop(self) - int: res self.stacks[self.maxCnt].pop() self.cnt[res] - 1 if not self.stacks[self.maxCnt]: self.maxCnt - 1 return resclass FreqStack { private MapInteger, Integer cnt; private MapInteger, StackInteger stacks; private int maxCnt; public FreqStack() { cnt new HashMap(); stacks new HashMap(); maxCnt 0; } public void push(int val) { int valCnt cnt.getOrDefault(val, 0) 1; cnt.put(val, valCnt); if (valCnt maxCnt) { maxCnt valCnt; stacks.putIfAbsent(valCnt, new Stack()); } stacks.get(valCnt).push(val); } public int pop() { int res stacks.get(maxCnt).pop(); cnt.put(res, cnt.get(res) - 1); if (stacks.get(maxCnt).isEmpty()) { maxCnt--; } return res; } }class FreqStack { public: unordered_mapint, int cnt; unordered_mapint, stackint stacks; int maxCnt; FreqStack() { maxCnt 0; } void push(int val) { int valCnt cnt[val]; if (valCnt maxCnt) { maxCnt valCnt; stacks[valCnt] stackint(); } stacks[valCnt].push(val); } int pop() { int res stacks[maxCnt].top(); stacks[maxCnt].pop(); cnt[res]--; if (stacks[maxCnt].empty()) { maxCnt--; } return res; } };class FreqStack { constructor() { this.cnt new Map(); this.stacks new Map(); this.maxCnt 0; } /** * param {number} val * return {void} */ push(val) { const valCnt (this.cnt.get(val) || 0) 1; this.cnt.set(val, valCnt); if (valCnt this.maxCnt) { this.maxCnt valCnt; if (!this.stacks.has(valCnt)) { this.stacks.set(valCnt, []); } } this.stacks.get(valCnt).push(val); } /** * return {number} */ pop() { const res this.stacks.get(this.maxCnt).pop(); this.cnt.set(res, this.cnt.get(res) - 1); if (this.stacks.get(this.maxCnt).length 0) { this.maxCnt--; } return res; } }type FreqStack struct { cnt map[int]int stacks map[int][]int maxCnt int } func Constructor() FreqStack { return FreqStack{ cnt: make(map[int]int), stacks: make(map[int][]int), maxCnt: 0, } } func (this *FreqStack) Push(val int) { this.cnt[val] valCnt : this.cnt[val] if valCnt this.maxCnt { this.maxCnt valCnt this.stacks[valCnt] []int{} } this.stacks[valCnt] append(this.stacks[valCnt], val) } func (this *FreqStack) Pop() int { stack : this.stacks[this.maxCnt] res : stack[len(stack)-1] this.stacks[this.maxCnt] stack[:len(stack)-1] this.cnt[res]-- if len(this.stacks[this.maxCnt]) 0 { this.maxCnt-- } return res }struct FreqStack { cnt: HashMapi32, i32, stacks: HashMapi32, Veci32, max_cnt: i32, } impl FreqStack { fn new() - Self { FreqStack { cnt: HashMap::new(), stacks: HashMap::new(), max_cnt: 0, } } fn push(mut self, val: i32) { let val_cnt *self.cnt.entry(val).or_insert(0) 1; self.cnt.insert(val, val_cnt); if val_cnt self.max_cnt { self.max_cnt val_cnt; self.stacks.entry(val_cnt).or_insert_with(Vec::new); } self.stacks.get_mut(val_cnt).unwrap().push(val); } fn pop(mut self) - i32 { let res self.stacks.get_mut(self.max_cnt).unwrap().pop().unwrap(); *self.cnt.get_mut(res).unwrap() - 1; if self.stacks[self.max_cnt].is_empty() { self.max_cnt - 1; } res } }仓库源码印证本仓库 python/0895-maximum-frequency-stack.py 正是采用本解法的精简实现其核心逻辑与上文 Python 代码完全一致push中先自增计数、在突破maxCnt时新建层级栈pop中弹栈后检查空栈并回退maxCnt。同样采用哈希表版「栈的栈」的还有 java/0895-maximum-frequency-stack.java 与 typescript/0895-maximum-frequency-stack.ts而 cpp/0895-maximum-frequency-stack.cpp、rust/0895-maximum-frequency-stack.rs 则是下文解法四动态数组版的落地实现。这说明仓库内的社区提交覆盖了多种等价写法均可通过 LeetCode 895 的测试用例。时间复杂度与空间复杂度时间复杂度push与pop均为 O(1)哈希表读写 栈顶操作。空间复杂度O(n)。n 为栈中元素总数。注意由于同一元素出现在多个频率层级stacks中保存的元素副本总数等于push调用总次数因此空间仍为 O(n)。解法四栈的栈动态数组实现思路解法三用哈希表做「频率 → 栈」的映射由于频率从 1 开始且连续增长完全可以退化为动态数组列表数组下标即频率层级stacks[1]、stacks[2]、… 依次对应各频率的栈。此时最后一个非空栈的下标天然等于当前最大频率无需单独维护maxCntpop时直接从数组末尾的栈弹出即可弹空后把末尾空栈移除。算法步骤初始化频率哈希表cnt和列表stacks其中stacks[0]放入一个空占位栈频率从 1 开始。push(val)cnt[val]加一得到valCnt若valCnt len(stacks)说明到达了新的最高频率追加一个新空栈把val压入stacks[valCnt]。pop()从stacks[-1]最后一个栈弹出元素rescnt[res]减一若该栈弹空则将其从列表移除返回res。多语言实现class FreqStack: def __init__(self): self.cnt {} self.stacks [[]] def push(self, val: int) - None: valCnt 1 self.cnt.get(val, 0) self.cnt[val] valCnt if valCnt len(self.stacks): self.stacks.append([]) self.stacks[valCnt].append(val) def pop(self) - int: res self.stacks[-1].pop() self.cnt[res] - 1 if not self.stacks[-1]: self.stacks.pop() return respublic class FreqStack { private MapInteger, Integer cnt; private ListStackInteger stacks; public FreqStack() { cnt new HashMap(); stacks new ArrayList(); stacks.add(new Stack()); } public void push(int val) { int valCnt cnt.getOrDefault(val, 0) 1; cnt.put(val, valCnt); if (valCnt stacks.size()) { stacks.add(new Stack()); } stacks.get(valCnt).push(val); } public int pop() { StackInteger topStack stacks.get(stacks.size() - 1); int res topStack.pop(); cnt.put(res, cnt.get(res) - 1); if (topStack.isEmpty()) { stacks.remove(stacks.size() - 1); } return res; } }class FreqStack { public: unordered_mapint, int cnt; vectorstackint stacks; FreqStack() { stacks.push_back(stackint()); } void push(int val) { int valCnt cnt[val]; if (valCnt stacks.size()) { stacks.push_back(stackint()); } stacks[valCnt].push(val); } int pop() { stackint topStack stacks.back(); int res topStack.top(); topStack.pop(); if (topStack.empty()) { stacks.pop_back(); } cnt[res]--; return res; } };class FreqStack { constructor() { this.cnt new Map(); this.stacks [[]]; } /** * param {number} val * return {void} */ push(val) { const valCnt (this.cnt.get(val) || 0) 1; this.cnt.set(val, valCnt); if (valCnt this.stacks.length) { this.stacks.push([]); } this.stacks[valCnt].push(val); } /** * return {number} */ pop() { const topStack this.stacks[this.stacks.length - 1]; const res topStack.pop(); this.cnt.set(res, this.cnt.get(res) - 1); if (topStack.length 0) { this.stacks.pop(); } return res; } }type FreqStack struct { cnt map[int]int stacks [][]int } func Constructor() FreqStack { return FreqStack{ cnt: make(map[int]int), stacks: [][]int{{}}, } } func (this *FreqStack) Push(val int) { this.cnt[val] valCnt : this.cnt[val] if valCnt len(this.stacks) { this.stacks append(this.stacks, []int{}) } this.stacks[valCnt] append(this.stacks[valCnt], val) } func (this *FreqStack) Pop() int { lastStack : this.stacks[len(this.stacks)-1] res : lastStack[len(lastStack)-1] this.stacks[len(this.stacks)-1] lastStack[:len(lastStack)-1] this.cnt[res]-- if len(this.stacks[len(this.stacks)-1]) 0 { this.stacks this.stacks[:len(this.stacks)-1] } return res }struct FreqStack { cnt: HashMapi32, usize, stacks: VecVeci32, } impl FreqStack { fn new() - Self { FreqStack { cnt: HashMap::new(), stacks: vec![vec![]], } } fn push(mut self, val: i32) { let val_cnt *self.cnt.entry(val).or_insert(0) 1; self.cnt.insert(val, val_cnt); if val_cnt self.stacks.len() { self.stacks.push(vec![]); } self.stacks[val_cnt].push(val); } fn pop(mut self) - i32 { let res self.stacks.last_mut().unwrap().pop().unwrap(); *self.cnt.get_mut(res).unwrap() - 1; if self.stacks.last().unwrap().is_empty() { self.stacks.pop(); } res } }仓库源码印证cpp/0895-maximum-frequency-stack.cpp 是动态数组版的经典实现stacks为vectorvectorintpush时若k stacks.size()则新建层级pop时取stacks.back().back()并在弹空后stacks.pop_back()逻辑与本解法完全对应。rust/0895-maximum-frequency-stack.rs 同样采用VecVeci32动态数组方案。时间复杂度与空间复杂度时间复杂度push与pop均为 O(1)数组尾部追加/删除均摊。空间复杂度O(n)。n 为栈中元素总数。相比解法三省去了哈希表到栈的间接映射且天然避免了maxCnt的维护是面试中最简洁优雅的写法。四种解法复杂度对比解法push 时间复杂度pop 时间复杂度空间复杂度核心数据结构备注暴力单栈 扫描O(1)O(n)O(n)栈 哈希表正确但大数据下超时最大堆O(log n)O(log n)O(n)堆 哈希表堆内可能残留过期条目栈的栈哈希表O(1)O(1)O(n)哈希表 哈希表需维护maxCnt并注意空栈回退栈的栈动态数组O(1)O(1)O(n)哈希表 列表末尾栈即最大频率最简洁常见陷阱与调试要点1. 同频次平局处理错误多个元素共享最高频率时必须弹出最近压入的那一个。常见错误是随意弹出任意一个最大频率元素或弹出最早出现而非最后出现的元素。堆解法通过把插入次序index作为次级排序键解决「栈的栈」解法则天然利用每个频率层级内部栈的 LIFO 顺序保证「最近优先」。2. pop 后忘记递减频率弹出元素后必须同步将其频率减一。若遗漏数据结构会误以为该元素仍处于原频率导致后续操作全部错乱。cnt频率表和按频率索引的结构stacks必须保持一致更新。3. 最大频率跟踪器管理失误「栈的栈哈希表」用maxCnt决定从哪个栈弹出。一个隐蔽的 bug当stacks[maxCnt]弹空后没有递减maxCnt下一次pop将访问空栈。务必在每次pop后检查当前频率栈是否为空为空则maxCnt--。4. 单栈 扫描的 O(n) 隐患单栈反向扫描在概念上最简单但pop是 O(n)大输入下必然超时。核心洞察是同一元素被多次压入时会同时存在于多个频率层级「栈的栈」正是利用这一点把两种操作压到 O(1)。5. 堆中的过期条目堆解法中元素被 pop 后频率变化但旧条目仍残留在堆中。这不影响正确性因为cnt是权威频率来源堆顶取出的是合法条目但会占用额外内存。部分实现会引入惰性删除lazy deletion简单做法则是接受堆中存在过期条目始终以cnt为准。仓库多语言实现速查本题在仓库中以0895-maximum-frequency-stack.*命名覆盖多种语言可直接对照学习文档articles/maximum-frequency-stack.mdPythonpython/0895-maximum-frequency-stack.py栈的栈·哈希表版Javajava/0895-maximum-frequency-stack.java栈的栈·哈希表版TypeScripttypescript/0895-maximum-frequency-stack.ts栈的栈·哈希表版Ccpp/0895-maximum-frequency-stack.cpp栈的栈·动态数组版Rustrust/0895-maximum-frequency-stack.rs栈的栈·动态数组版JavaScriptjavascript/0895-maximum-frequency-stack.jsKotlinkotlin/0895-maximum-frequency-stack.kt仓库 README.md 说明这是一个服务于 NeetCode.io 的 LeetCode 多语言题解仓库文章与各语言源码一一对应可直接用于刷题对照与面试复盘。总结最大频率栈是一道经典的「数据结构组合设计」题四种解法构成一条清晰的进阶路径暴力先保证正确暴露 O(n) pop 的性能瓶颈最大堆用(频率, 插入次序, 值)三元组把 O(n) 降到 O(log n)理解平局处理与过期条目栈的栈哈希表按频率分层pop 恒定 O(1)需细致维护maxCnt栈的栈动态数组用数组下标替代哈希键末尾栈即最大频率实现最简洁。掌握这条从朴素到最优的演化路径比背下最终答案更有价值——它训练的是「当标准数据结构无法满足需求时如何组合多个结构并拆解排序优先级」的设计能力这正是面试与真实系统中数据结构的通用思维模式。【免费下载链接】leetcodeLeetcode solutions项目地址: https://gitcode.com/GitHub_Trending/leetcode1/leetcode创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表