🧠
Alternative Approach (Using Heap with Timestamp)
💡 This approach uses a max heap to always pop the element with highest frequency and most recent timestamp, demonstrating a priority queue based solution.
Intuition
Store elements in a max heap keyed by frequency and timestamp to pop the correct element efficiently.
Algorithm
- Maintain a frequency map for each element.
- Maintain a global timestamp counter incremented on each push.
- Push elements into a max heap keyed by (frequency, timestamp).
- For pop(), pop from heap, decrement frequency, and return element.
💡 The challenge is managing frequency updates and timestamps to maintain correct priority in the heap.
import heapq
class FreqStack:
def __init__(self):
self.freq = {}
self.heap = []
self.time = 0
def push(self, val: int) -> None:
self.freq[val] = self.freq.get(val, 0) + 1
self.time += 1
# Use negative freq and time for max heap behavior
heapq.heappush(self.heap, (-self.freq[val], -self.time, val))
def pop(self) -> int:
freq, time, val = heapq.heappop(self.heap)
self.freq[val] -= 1
if self.freq[val] == 0:
del self.freq[val]
return val
# Driver code
if __name__ == '__main__':
fs = FreqStack()
fs.push(5)
fs.push(7)
fs.push(5)
fs.push(7)
fs.push(4)
fs.push(5)
print(fs.pop()) # 5
print(fs.pop()) # 7
print(fs.pop()) # 5
print(fs.pop()) # 4
Line Notes
self.freq = {}Map to track frequency of each element
self.heap = []Heap to store elements keyed by frequency and timestamp
self.time = 0Global timestamp incremented on each push to maintain recency
self.freq[val] = self.freq.get(val, 0) + 1Increment frequency for pushed element
self.time += 1Increment timestamp for recency ordering
heapq.heappush(self.heap, (-self.freq[val], -self.time, val))Push tuple with negative freq and time for max heap behavior
freq, time, val = heapq.heappop(self.heap)Pop element with highest freq and most recent time
self.freq[val] -= 1Decrement frequency after pop
if self.freq[val] == 0: del self.freq[val]Clean up frequency map when frequency reaches zero
import java.util.*;
class FreqStack {
Map<Integer, Integer> freq;
PriorityQueue<int[]> heap;
int time;
public FreqStack() {
freq = new HashMap<>();
time = 0;
heap = new PriorityQueue<>((a, b) -> {
if (a[0] != b[0]) return b[0] - a[0];
return b[1] - a[1];
});
}
public void push(int val) {
freq.put(val, freq.getOrDefault(val, 0) + 1);
time++;
// Push negative freq and time for max heap behavior
heap.offer(new int[]{-freq.get(val), -time, val});
}
public int pop() {
int[] top = heap.poll();
int val = top[2];
freq.put(val, freq.get(val) - 1);
if (freq.get(val) == 0) freq.remove(val);
return val;
}
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
}
}
Line Notes
Map<Integer, Integer> freq;Map to track frequency of each element
PriorityQueue<int[]> heap;Heap storing arrays of [freq, time, val] with max heap behavior
int time;Global timestamp incremented on each push to maintain recency
freq.put(val, freq.getOrDefault(val, 0) + 1);Increment frequency for pushed element
time++;Increment timestamp for recency ordering
heap.offer(new int[]{-freq.get(val), -time, val});Add element to heap with negative frequency and time for max heap
int[] top = heap.poll();Pop element with highest frequency and most recent time
freq.put(val, freq.get(val) - 1);Decrement frequency after pop
if (freq.get(val) == 0) freq.remove(val);Remove element from map if frequency zero
#include <iostream>
#include <unordered_map>
#include <queue>
#include <tuple>
using namespace std;
class FreqStack {
unordered_map<int, int> freq;
priority_queue<tuple<int, int, int>> heap; // freq, time, val
int time;
public:
FreqStack() : time(0) {}
void push(int val) {
freq[val]++;
time++;
// Push negative freq and time for max heap behavior
heap.emplace(freq[val], time, val);
}
int pop() {
auto [f, t, val] = heap.top();
heap.pop();
freq[val]--;
if (freq[val] == 0) freq.erase(val);
return val;
}
};
int main() {
FreqStack fs;
fs.push(5);
fs.push(7);
fs.push(5);
fs.push(7);
fs.push(4);
fs.push(5);
cout << fs.pop() << "\n"; // 5
cout << fs.pop() << "\n"; // 7
cout << fs.pop() << "\n"; // 5
cout << fs.pop() << "\n"; // 4
return 0;
}
Line Notes
unordered_map<int, int> freq;Map to track frequency of each element
priority_queue<tuple<int, int, int>> heap;Max heap keyed by frequency and timestamp
int time;Global timestamp incremented on each push to maintain recency
freq[val]++;Increment frequency for pushed element
time++;Increment timestamp for recency ordering
heap.emplace(freq[val], time, val);Push tuple into heap (note: C++ priority_queue is max heap by default)
auto [f, t, val] = heap.top();Get element with highest frequency and most recent time
heap.pop();Remove element from heap
freq[val]--;Decrement frequency after pop
if (freq[val] == 0) freq.erase(val);Remove element from map if frequency zero
class FreqStack {
constructor() {
this.freq = new Map();
this.heap = [];
this.time = 0;
}
push(val) {
this.freq.set(val, (this.freq.get(val) || 0) + 1);
this.time++;
this.heap.push({freq: this.freq.get(val), time: this.time, val});
this.heap.sort((a, b) => b.freq - a.freq || b.time - a.time);
}
pop() {
const top = this.heap.shift();
this.freq.set(top.val, this.freq.get(top.val) - 1);
if (this.freq.get(top.val) === 0) this.freq.delete(top.val);
return top.val;
}
}
// Test
const fs = new FreqStack();
fs.push(5);
fs.push(7);
fs.push(5);
fs.push(7);
fs.push(4);
fs.push(5);
console.log(fs.pop()); // 5
console.log(fs.pop()); // 7
console.log(fs.pop()); // 5
console.log(fs.pop()); // 4
Line Notes
this.freq = new Map()Map to track frequency of each element
this.heap = []Array to simulate heap (inefficient here, uses sort on every push)
this.time = 0Global timestamp incremented on each push to maintain recency
this.freq.set(val, (this.freq.get(val) || 0) + 1)Increment frequency for pushed element
this.time++Increment timestamp for recency ordering
this.heap.push({freq: this.freq.get(val), time: this.time, val})Add element with freq and time to array
this.heap.sort((a, b) => b.freq - a.freq || b.time - a.time)Sort heap to maintain max frequency and recency order (inefficient)
const top = this.heap.shift()Pop element with highest priority (max freq and most recent)
this.freq.set(top.val, this.freq.get(top.val) - 1)Decrement frequency after pop
if (this.freq.get(top.val) === 0) this.freq.delete(top.val)Remove element if frequency zero
TimeO(log n) per push and pop due to heap operations
SpaceO(n) for frequency map and heap
Heap operations dominate complexity, slower than stack per frequency approach
💡 For large n, this approach is slower but still acceptable; sorting in JS implementation is inefficient.
Interview Verdict: Accepted but less optimal
This approach is valid but less efficient than the stack per frequency approach and may be harder to implement correctly.