The O(n) Club: Maximum Frequency Stack, But Cooler
⚡ TL;DR
Your classic stack is LIFO: “Last one in, first one out.” But what if the boss suddenly wants you to pop the element that’s shown up most often? Enter Frequency Stack—a data structure with trust issues! You use maps to track who’s most popular and group stacks to track recency. In Java, it’s almost magic (minus the wand):
// Sketchy, but true summary void push(int x) { int freq = freqMap.getOrDefault(x, 0) + 1; freqMap.put(x, freq); group.computeIfAbsent(freq, z -> new Stack<>()).push(x); maxFreq = Math.max(maxFreq, freq); } int pop() { int x = group.get(maxFreq).pop(); freqMap.put(x, freqMap.get(x) - 1); if (group.get(maxFreq).isEmpty()) maxFreq--; return x; }
🧠 How Devs Usually Mess This Up
Look, if you use a regular stack, congratulations, you’ve made another boring stack. If you use a max heap, you’ll need timestamps or a crystal ball to settle tiebreakers. And if you accidentally track frequency per stack frame? You might as well code on a potato. Bottom line: the rookie moves here are assuming LIFO is enough, forgetting about ties, and mismanaging frequency like it’s a gym subscription.
🔍 What’s Actually Going On
This problem wants you to act like a nightclub bouncer with an Excel sheet—let the most frequent (and loudest) patron leave first, but if there’s a tie? The one who yelled most recently gets kicked out.
Practically, you need:
- freqMap: Maps each element to its frequency—keeps you from making stuff up.
- group: A stack for each frequency—so you always know which guests are double-dipping.
- maxFreq: The current most-annoying frequency.
Every push() drops your element on the stack for its frequency; every pop() grabs the latest from the stack with the highest frequency, then hands out a “please leave” coupon as you decrement its count.
🛠️ PseudoCode
- Push(x):
- Increment
freqMap[x] - If this is a new frequency, make a new stack in
group - Push
xontogroup[freq] maxFreq= bigger of oldmaxFreqorfreq
freq = freqMap.getOrDefault(x, 0) + 1; freqMap.put(x, freq); group.computeIfAbsent(freq, z -> new Stack<>()).push(x); maxFreq = Math.max(maxFreq, freq); - Increment
- Pop():
- Pop top item from
group[maxFreq] - Decrement its frequency in
freqMap - If
group[maxFreq]is now empty, reducemaxFreq - Return x (congratulations, you yeeted the worst offender)
x = group.get(maxFreq).pop(); freqMap.put(x, freqMap.get(x) - 1); if (group.get(maxFreq).isEmpty()) maxFreq--; return x; - Pop top item from
💻 The Code
import java.util.*;
class FreqStack {
private Map<integer integer> freqMap = new HashMap<>();
private Map<integer stack>> group = new HashMap<>();
private int maxFreq = 0;
public void push(int x) {
int freq = freqMap.getOrDefault(x, 0) + 1;
freqMap.put(x, freq);
group.computeIfAbsent(freq, z -> new Stack<>()).push(x);
maxFreq = Math.max(maxFreq, freq);
}
public int pop() {
Stack
<integer> stack = group.get(maxFreq);
int x = stack.pop();
freqMap.put(x, freqMap.get(x) - 1);
if (stack.isEmpty()) maxFreq--;
return x;
}
public static void main(String[] args) {
FreqStack fs = new FreqStack();
fs.push(5); fs.push(7); fs.push(5); fs.push(7); fs.push(4); fs.push(5);
System.out.println(fs.pop()); // 5
System.out.println(fs.pop()); // 7
System.out.println(fs.pop()); // 5
System.out.println(fs.pop()); // 4
}
}
</integer></integer></integer>
⚠️ Pitfalls, Traps & Runtime Smacks
- Empty Stack Drama: Pop when the stack is empty, and Java will repay you—with a runtime error as dramatic as your bug tracker.
- maxFreq Slip-Ups: Always update
maxFreq—otherwise, you might pop from an empty stack (awkward silence). - Tie-breakers: Never trust hash order. Always break ties with recency using real stacks.
- Performance Hype: Both
push()andpop()are O(1). Yes, that’s real. No, LinkedList O(1) memes here.
🧠 Interviewer Brain-Tattoo
“A regular stack is forgetful. A frequency stack? Unforgiving, petty, and always keeping score.”