Hi👋SpeedAlgo • Deliberate Practice & Cognitive Ergonomics for Software Engineers

An interactive algorithm mastery and technical interview preparation platform published by Hi👋WebEnterprise. Built for senior and staff software engineers preparing for rigorous coding screens at top tech companies (FAANG/MAMAA).

13 Core Algorithmic Patterns & 225 Practice Problems

  • 1. Two Pointers (16 Paradigms, 43 Problems): Opposite ends, sorted pair sums, palindrome verification, trapping rain water, 3Sum, container with most water — includes the Sliding Window and Fast & Slow Pointers paradigms (contiguous subarray invariants, longest substrings, Floyd's cycle detection, linked list middle).
  • 2. Binary Search (9 Paradigms, 14 Problems): Monotonic predicate partitioning (feasible(x)), boundary search, rotated sorted arrays, square roots, minimum ship capacity, median of two sorted arrays, matrix median on value range.
  • 3. Bit Manipulation (5 Paradigms, 11 Problems): Counting set bits, XOR cancellation, bit reversal, bitmask pairing, maximum XOR with a bitwise trie.
  • 4. Math & Geometry (8 Paradigms, 14 Problems): Sieve of Eratosthenes, integer/roman conversions, modular arithmetic, geometric simulation.
  • 5. Tree/Graph Depth-First Search (15 Paradigms, 24 Problems): Path sums, lowest common ancestor, tree diameter, validating BSTs, tree DP (House Robber III, Binary Tree Cameras).
  • 6. Tree/Graph Breadth-First Search (5 Paradigms, 12 Problems): Level-order traversals, shortest path in unweighted graphs, zig-zag traversals, rotting oranges, word ladders.
  • 7. Graphs (12 Paradigms, 22 Problems): Topological sort, cycle detection, Dijkstra's algorithm, bipartite graph validation, network delay.
  • 8. Backtracking (6 Paradigms, 14 Problems): Subsets, permutations, combinations, constraint satisfaction, pruning, N-Queens, Sudoku solver.
  • 9. Dynamic Programming (13 Paradigms, 28 Problems): Memoization vs tabulation, 0/1 knapsack, unbounded knapsack, coin change, edit distance, longest common subsequence.
  • 10. Heap / Priority Queue (9 Paradigms, 11 Problems): Running medians, top-k elements, interval scheduling, IPO, k-way merges.
  • 11. Advanced Data Structures (7 Paradigms, 17 Problems): Trie (prefix tree), Union-Find (Disjoint Set Union), LRU Cache, LFU Cache, range-sum queries with updates.
  • 12. Stack (5 Paradigms, 9 Problems): Next greater element, largest rectangle in histogram, remove k digits, decode string, min stack.
  • 13. Intervals & Greedy (2 Paradigms, 6 Problems): Merge intervals, interval scheduling, meeting rooms by sweep line, jump game.

4-Stage Deliberate Practice Framework

  1. Stage 1 (Compare & Learn): Read the pattern's mental model, loop invariant and Big-O proof, compare the pattern's template with the problem's solution side by side, and use the step-by-step debugger. The solution can also be shown in C#, Java, TypeScript, C++, Go or Rust for almost every problem.
  2. Stage 2 (Active Recall): Rebuild the solution from memory in a code editor, with an invariant checklist and optional progressive hints, and check it against a judged test suite.
  3. Stage 3 (AI Interview Coach, coming soon): A mock-interview stage still in development; for now, students go straight from Stage 2 to Stage 4.
  4. Stage 4 (Solve on Your Own): Solve a new problem on your own against a 15-minute timer; your code is graded against a test suite. Python and TypeScript run in your browser and C# runs on our server (design problems grade in Python and TypeScript).

Equipped with a spaced-repetition review hub on a fixed 7-step schedule (1 day up to 90 days), a two-pane Studio workspace, and study notes.

Pricing, Access & Commercial Terms

  • Core Curriculum: 100% Free. No credit card required.
  • Coins: New accounts get 40 free coins once, the daily claim adds +20 coins once a day, and inviting a friend earns you +25 coins when they complete their first practice step. These are the only ways to earn coins.
  • AI Coach: Each AI coach question costs 1-5 coins, priced by the server according to its size.
  • BYOK (Bring Your Own Key): AI coaching is free with your own Google Gemini, OpenAI or OpenRouter API key (BYOK).
  • Extras: Coins also unlock extras for 24 hours: a Recall hint level (1 coin), a Solve solution reveal (2), a LeetCode problem card's solutions (1) and a pattern's extra canonical problems (1).
  • Payments & Refunds: Nothing on the site is sold for money: coins can only be earned, never bought. There are no subscriptions or charges, so there is nothing to refund.
  • Platform Operator: Hi👋WebEnterprise. Support & policies at hispeedalgo.com.
Skip to main content
Hi👋SpeedAlgo

Invariant-First Algorithmic Mastery

Arena
238Items
Theory Context•Advanced Data Structures
HardLC 460

LFU Cache (LeetCode 460)

Target Frequency:GoogleAmazonMicrosoft

A cache with a fixed capacity should evict its least frequently used key once full, breaking ties between equally-frequent keys by evicting whichever one was touched longest ago.

Build an LFUCache class:

  • LFUCache(int capacity) sets up the cache with the given capacity.
  • int get(int key) returns the value stored for key, or -1 if key isn't present.
  • void put(int key, int value) overwrites key's value if it's already present, or inserts it otherwise; once the cache is at capacity, this first evicts the least frequently used key (the tie-break above applies).

Every key carries a use counter: a fresh put sets it to 1, and both get and put on an existing key bump its counter by one. The least frequently used key is simply the one with the smallest counter.

Both get and put must run in O(1) average time.

Worked Examples

Example 1
Input:["LFUCache", "put", "put", "get", "put", "get", "get", "put", "get", "get", "get"] [[2], [1, 1], [2, 2], [1], [3, 3], [2], [3], [4, 4], [1], [3], [4]]
Output:[null, null, null, 1, null, -1, 3, null, -1, 3, 4]
Explanation: put(1,1) cnt(1)=1; put(2,2) cnt(2)=1; get(1)->1, cnt(1)=2; put(3,3) evicts 2 (cnt=1 is min), cnt(3)=1; get(2)->-1; get(3)->3, cnt(3)=2; put(4,4): 1 and 3 tie at cnt=2, 1 is LRU so evict 1, cnt(4)=1; get(1)->-1; get(3)->3, cnt(3)=3; get(4)->4, cnt(4)=2.

⚖️Formal Constraints & Bounds

  • 1 <= capacity <= 104

  • 0 <= key <= 105

  • 0 <= value <= 109

  • At most 2 * 105 calls will be made to get and put.

Deep-Dive & Conceptual Insights

Core Insight

Frequencies only ever change by exactly +1 per access, so one small doubly-linked-list bucket per frequency (plus a running min_freq pointer that only advances when its bucket empties) delivers O(1) promotion and O(1) eviction, with ties among equal frequencies broken by LRU order within the bucket.

Real-World Scenario & Production Applications

CPU cache replacement policies weighting access frequency over recency, database buffer pool eviction, CDN caching for content whose popularity (not just recency) determines retention value.

Subproblems & Recurrence Decomposition3 Phases

🧩Subproblem 1: Two-Level Map -- Key to Node, Frequency to Bucket

One hash map (key_node) resolves any key to its node in O(1). A second hash map (freq_bucket) resolves any frequency value to the doubly-linked-list bucket of every key currently at that exact frequency.

Mathematical Recurrence / Code Invariant
self.key_node = {}      # key -> Node(value, freq)
self.freq_bucket = {}   # freq -> DLList of keys at that freq

Step-by-Step Execution Trace Table

StepOperationmin_freqFrequency Buckets (freq -> [Keys])Evicted KeyOutput
1LFUCache(2)0{}-null
2put(1, 1)1{1: [1]}-null
3put(2, 2)1{1: [2, 1]} (MRU -> LRU)-null
4get(1)1{1: [2], 2: [1]}-1 (key 1 freq promoted to 2)
5put(3, 3)1Capacity full! Evict LRU from min_freq=1 (key 2). {1: [3], 2: [1]}2null
6get(2)1{1: [3], 2: [1]}--1 (key 2 was evicted)
7get(3)2Key 3 promoted: freq 2. Bucket 1 now empty, min_freq = 2. {2: [3, 1]}-3
Code Shape
Archetype Code Shape
Python
1self.key_node = {} # key -> Node
2self.freq_bucket = {} # freq -> DLList (LRU-ordered within freq)
3self.min_freq tracks the lowest occupied bucket
4get/put on existing key -> _bump_freq: pop bucket[f], push front bucket[f+1]
5put on new key at capacity -> evict tail of bucket[min_freq]

Conceptual Narrative

LRU Cache only asks "when was this key touched last?" LFU Cache asks a harder two-dimensional question: "how often has this key been touched, and among the least frequent, which is stalest?"—in strict O(1) time.

🧭 Conceptual Foundation & Pattern Intuition

Least Frequently Used (LFU) evicts the key with the lowest access frequency. If multiple keys tie for minimum frequency, it evicts the least recently used among them. A min-heap tracking frequency costs O(log⁡N)O(\log N)O(logN) on every get and put, which violates the strict O(1)O(1)O(1) requirement of LC 460. How do we achieve strict O(1)O(1)O(1) without sorting? The key insight is that access frequencies only ever change by +1+1+1 per operation:

  • A key's frequency starts at 1 and increments by exactly 1 on each access. It never jumps arbitrarily.
  • Instead of a single sorted structure, we maintain a ladder of frequency buckets (freq_to_dll), where each bucket is its own independent Doubly-Linked List containing all nodes that share that exact frequency.
  • Inside each frequency bucket, nodes are ordered by recency (LRU order).
  • We maintain a global scalar min_freq. When an item's frequency increases from FFF to F+1F+1F+1, it is unlinked from bucket FFF and prepended to bucket F+1F+1F+1. If bucket FFF becomes empty and F == min_freq, we increment min_freq += 1.
  • When eviction is required, we simply pop the tail node from bucket min_freq.
🗄️ The Analogy: The Tiered Airport Lounge Priority Shelves

Imagine an airport lounge with luggage shelves numbered by tier: Shelf 1 (visited once), Shelf 2 (visited twice), Shelf 3, etc. Within any shelf, bags are lined up left-to-right by arrival time. When a passenger visits their bag on Shelf 2, the attendant unlinks it from Shelf 2 and places it at the front of Shelf 3. If Shelf 2 was the lowest occupied shelf and just became completely empty, the attendant moves the "lowest tier" sticky note from Shelf 2 to Shelf 3. When the lounge exceeds capacity, the attendant walks directly to the lowest occupied shelf and removes the bag at the very back—guaranteeing least-frequent eviction with an LRU tiebreaker in constant time.

🔑 Why It Works

Tracking min_freq requires zero search: fresh keys reset it to 1, while existing key updates only ever increment it when its former bucket empties out.

  • Failing to update min_freq on node promotion: When a node with frequency equal to min_freq is accessed and its count becomes min_freq + 1, if its frequency list becomes empty, min_freq must increment by 1.

  • Tie-breaking eviction violation: When multiple keys share the lowest frequency, the problem requires evicting the least recently used among them. Each frequency bucket must be a doubly-linked list ordered by access recency.

  • Updating frequency in O(N)O(N)O(N) search instead of O(1)O(1)O(1) node relocation: Using a heap or linear scan to track minimum frequencies results in O(N)O(N)O(N) operations. A map from frequency to doubly-linked list (freq_map[f] = DoublyLinkedList()) guarantees strict O(1)O(1)O(1) get and put.

Senior SWE Reasoning Architecture

4-Phase Thought Process Model

Pattern Recognition Signals

The 10-second spot

Key-value cache bounded by capacity + O(1) get/put + eviction by LEAST FREQUENTLY used, tie-broken by least recently used.

Formulating the Predicate & Invariants

Turning intuition into a boolean rule

Invariant: a key's frequency only ever increases by exactly 1 per access, so it moves from bucket f to bucket f+1 in O(1); min_freq only needs to advance when bucket[min_freq] becomes empty, never requiring a scan.

Silent Failure Traps & Edge Cases

Where confident candidates still lose points

  • Forgetting to reset min_freq to 1 on every brand-new key insertion (a fresh key is, by definition, the new minimum frequency).

  • Not deleting an emptied frequency bucket from the freq_bucket map, causing stale empty buckets to be mistaken for the min_freq target later.

  • Breaking the LRU tiebreak within a frequency bucket: inserting at the wrong end (must insert_front so eviction always pops the tail = least recently used at that frequency).

  • Using a single global frequency counter instead of per-key freq, which loses the ability to bucket by exact frequency.

The 60-Second Interview Pitch

Say this out loud before you type a single line

"I pair a hash map (key -> Node holding value and freq) with a second hash map (freq -> doubly-linked-list bucket of keys at that exact frequency, LRU-ordered). A running min_freq pointer always identifies the lowest occupied bucket. On get or put-on-existing-key, I remove the node from its current bucket, bump freq by 1, and reinsert at the front of the new bucket -- advancing min_freq only if the old bucket just emptied. On put of a brand-new key at capacity, I evict the tail of bucket[min_freq] (the least-recently-used key among the least-frequently-used), insert the new key at frequency 1, and reset min_freq to 1. Every operation is O(1) pointer surgery."

Big-O Invariant Derivation

Complexity & Mathematical Proof

TIME COMPLEXITY

O(1) Average

Look at both get(key) and put(key, value): key_node gives O(1) average lookup of the node holding value and freq. freq_bucket gives O(1) average lookup of the doubly-linked-list bucket for any frequency. Removing a node from its bucket and reinserting at the front of the next bucket (_bump_freq) touches a fixed number of pointer fields, O(1). min_freq is only ever read or incremented by 1, never recomputed by scanning. Eviction pops the tail of bucket[min_freq], also O(1). Every operation is strictly O(1) average time.

SPACE COMPLEXITY

O(C) Auxiliary

Look at memory allocation: the cache holds at most capacity entries, so key_node holds O(C) entries. freq_bucket holds at most O(C) buckets (one per distinct frequency currently present, bounded by C), each bucket's total node count summing to O(C) across all buckets. Total auxiliary space is O(C).

Formal Recurrence Relation

T(get)=O(1),T(put)=O(1)T(\text{get}) = O(1), \quad T(\text{put}) = O(1)T(get)=O(1),T(put)=O(1)

Derivation Progression

Hash Map Direct Node + Bucket Lookup

Tlookup=O(1)T_{\text{lookup}} = O(1)Tlookup​=O(1)

key_node locates the node; freq_bucket locates its frequency's doubly-linked-list bucket, both O(1) average.

Frequency Bump Splice

Tbump=4-6 pointer mutations=O(1)T_{\text{bump}} = 4\text{-}6 \text{ pointer mutations} = O(1)Tbump​=4-6 pointer mutations=O(1)

Removing from bucket[f] and inserting at the front of bucket[f+1] (creating it if absent) is fixed-cost pointer surgery.

min_freq Maintenance

Tmin_freq=O(1)T_{\text{min\_freq}} = O(1)Tmin_freq​=O(1)

min_freq is incremented by exactly 1 only when its own bucket becomes empty, and reset to 1 on a fresh insert -- never recomputed by scanning all buckets.

Variable Definitions

CCC

Maximum cache capacity

QQQ

Total number of get and put operations performed

Memory Architecture & Bounds

🟣 Call Stack

O(1) Non-recursive method calls

🔵 Auxiliary Heap

O(C) key_node map of size C + freq_bucket map whose bucket node counts sum to C

🟢 Output Space

O(1) Scalar return values

Boundary Best / Worst Cases

Best Case

O(1)O(1)O(1) for both get and put operations.

Average Case

O(1)O(1)O(1) standard hash table distribution.

Worst Case

O(1)O(1)O(1) amortized average (O(C)O(C)O(C) in rare catastrophic hash collision degeneration).

Pointer Invariant Transition Progression

Pointer Invariant Transition Progression
Synthesizing vector architecture diagram...
Staff+ Engineering Perspective

Senior SWE Deconstruction & Hardware Caveats

ARCHITECTURAL SIGNALS & INTERVIEW TRIGGERS

Triggers: "LFU Cache", "tie-breaker is least recently used", "O(1) time complexity". Two-level indexing: keys are grouped by frequency, and within the same frequency, ordered by recency. A Senior SWE uses key_to_node map + freq_to_dll map + min_freq integer.

CONSTRAINTS & BOUNDS

Capacity ≤104\le 10^4≤104, up to 2×1052 \times 10^52×105 calls. Strictly O(1)O(1)O(1) per get and put.

FAANG PRODUCTION TRAPS & EDGE CASES

Capacity 0 base case (no-op on put, return -1 on get).

Theory Context•Advanced Data Structures
HardLC 460

LFU Cache (LeetCode 460)

Target Frequency:GoogleAmazonMicrosoft

A cache with a fixed capacity should evict its least frequently used key once full, breaking ties between equally-frequent keys by evicting whichever one was touched longest ago.

Build an LFUCache class:

  • LFUCache(int capacity) sets up the cache with the given capacity.
  • int get(int key) returns the value stored for key, or -1 if key isn't present.
  • void put(int key, int value) overwrites key's value if it's already present, or inserts it otherwise; once the cache is at capacity, this first evicts the least frequently used key (the tie-break above applies).

Every key carries a use counter: a fresh put sets it to 1, and both get and put on an existing key bump its counter by one. The least frequently used key is simply the one with the smallest counter.

Both get and put must run in O(1) average time.

Worked Examples

Example 1
Input:["LFUCache", "put", "put", "get", "put", "get", "get", "put", "get", "get", "get"] [[2], [1, 1], [2, 2], [1], [3, 3], [2], [3], [4, 4], [1], [3], [4]]
Output:[null, null, null, 1, null, -1, 3, null, -1, 3, 4]
Explanation: put(1,1) cnt(1)=1; put(2,2) cnt(2)=1; get(1)->1, cnt(1)=2; put(3,3) evicts 2 (cnt=1 is min), cnt(3)=1; get(2)->-1; get(3)->3, cnt(3)=2; put(4,4): 1 and 3 tie at cnt=2, 1 is LRU so evict 1, cnt(4)=1; get(1)->-1; get(3)->3, cnt(3)=3; get(4)->4, cnt(4)=2.

⚖️Formal Constraints & Bounds

  • 1 <= capacity <= 104

  • 0 <= key <= 105

  • 0 <= value <= 109

  • At most 2 * 105 calls will be made to get and put.

Deep-Dive & Conceptual Insights

Core Insight

Frequencies only ever change by exactly +1 per access, so one small doubly-linked-list bucket per frequency (plus a running min_freq pointer that only advances when its bucket empties) delivers O(1) promotion and O(1) eviction, with ties among equal frequencies broken by LRU order within the bucket.

Real-World Scenario & Production Applications

CPU cache replacement policies weighting access frequency over recency, database buffer pool eviction, CDN caching for content whose popularity (not just recency) determines retention value.

Subproblems & Recurrence Decomposition3 Phases

🧩Subproblem 1: Two-Level Map -- Key to Node, Frequency to Bucket

One hash map (key_node) resolves any key to its node in O(1). A second hash map (freq_bucket) resolves any frequency value to the doubly-linked-list bucket of every key currently at that exact frequency.

Mathematical Recurrence / Code Invariant
self.key_node = {}      # key -> Node(value, freq)
self.freq_bucket = {}   # freq -> DLList of keys at that freq

Step-by-Step Execution Trace Table

StepOperationmin_freqFrequency Buckets (freq -> [Keys])Evicted KeyOutput
1LFUCache(2)0{}-null
2put(1, 1)1{1: [1]}-null
3put(2, 2)1{1: [2, 1]} (MRU -> LRU)-null
4get(1)1{1: [2], 2: [1]}-1 (key 1 freq promoted to 2)
5put(3, 3)1Capacity full! Evict LRU from min_freq=1 (key 2). {1: [3], 2: [1]}2null
6get(2)1{1: [3], 2: [1]}--1 (key 2 was evicted)
7get(3)2Key 3 promoted: freq 2. Bucket 1 now empty, min_freq = 2. {2: [3, 1]}-3
Code Shape
Archetype Code Shape
Python
1self.key_node = {} # key -> Node
2self.freq_bucket = {} # freq -> DLList (LRU-ordered within freq)
3self.min_freq tracks the lowest occupied bucket
4get/put on existing key -> _bump_freq: pop bucket[f], push front bucket[f+1]
5put on new key at capacity -> evict tail of bucket[min_freq]

Conceptual Narrative

LRU Cache only asks "when was this key touched last?" LFU Cache asks a harder two-dimensional question: "how often has this key been touched, and among the least frequent, which is stalest?"—in strict O(1) time.

🧭 Conceptual Foundation & Pattern Intuition

Least Frequently Used (LFU) evicts the key with the lowest access frequency. If multiple keys tie for minimum frequency, it evicts the least recently used among them. A min-heap tracking frequency costs O(log⁡N)O(\log N)O(logN) on every get and put, which violates the strict O(1)O(1)O(1) requirement of LC 460. How do we achieve strict O(1)O(1)O(1) without sorting? The key insight is that access frequencies only ever change by +1+1+1 per operation:

  • A key's frequency starts at 1 and increments by exactly 1 on each access. It never jumps arbitrarily.
  • Instead of a single sorted structure, we maintain a ladder of frequency buckets (freq_to_dll), where each bucket is its own independent Doubly-Linked List containing all nodes that share that exact frequency.
  • Inside each frequency bucket, nodes are ordered by recency (LRU order).
  • We maintain a global scalar min_freq. When an item's frequency increases from FFF to F+1F+1F+1, it is unlinked from bucket FFF and prepended to bucket F+1F+1F+1. If bucket FFF becomes empty and F == min_freq, we increment min_freq += 1.
  • When eviction is required, we simply pop the tail node from bucket min_freq.
🗄️ The Analogy: The Tiered Airport Lounge Priority Shelves

Imagine an airport lounge with luggage shelves numbered by tier: Shelf 1 (visited once), Shelf 2 (visited twice), Shelf 3, etc. Within any shelf, bags are lined up left-to-right by arrival time. When a passenger visits their bag on Shelf 2, the attendant unlinks it from Shelf 2 and places it at the front of Shelf 3. If Shelf 2 was the lowest occupied shelf and just became completely empty, the attendant moves the "lowest tier" sticky note from Shelf 2 to Shelf 3. When the lounge exceeds capacity, the attendant walks directly to the lowest occupied shelf and removes the bag at the very back—guaranteeing least-frequent eviction with an LRU tiebreaker in constant time.

🔑 Why It Works

Tracking min_freq requires zero search: fresh keys reset it to 1, while existing key updates only ever increment it when its former bucket empties out.

  • Failing to update min_freq on node promotion: When a node with frequency equal to min_freq is accessed and its count becomes min_freq + 1, if its frequency list becomes empty, min_freq must increment by 1.

  • Tie-breaking eviction violation: When multiple keys share the lowest frequency, the problem requires evicting the least recently used among them. Each frequency bucket must be a doubly-linked list ordered by access recency.

  • Updating frequency in O(N)O(N)O(N) search instead of O(1)O(1)O(1) node relocation: Using a heap or linear scan to track minimum frequencies results in O(N)O(N)O(N) operations. A map from frequency to doubly-linked list (freq_map[f] = DoublyLinkedList()) guarantees strict O(1)O(1)O(1) get and put.

Senior SWE Reasoning Architecture

4-Phase Thought Process Model

Pattern Recognition Signals

The 10-second spot

Key-value cache bounded by capacity + O(1) get/put + eviction by LEAST FREQUENTLY used, tie-broken by least recently used.

Formulating the Predicate & Invariants

Turning intuition into a boolean rule

Invariant: a key's frequency only ever increases by exactly 1 per access, so it moves from bucket f to bucket f+1 in O(1); min_freq only needs to advance when bucket[min_freq] becomes empty, never requiring a scan.

Silent Failure Traps & Edge Cases

Where confident candidates still lose points

  • Forgetting to reset min_freq to 1 on every brand-new key insertion (a fresh key is, by definition, the new minimum frequency).

  • Not deleting an emptied frequency bucket from the freq_bucket map, causing stale empty buckets to be mistaken for the min_freq target later.

  • Breaking the LRU tiebreak within a frequency bucket: inserting at the wrong end (must insert_front so eviction always pops the tail = least recently used at that frequency).

  • Using a single global frequency counter instead of per-key freq, which loses the ability to bucket by exact frequency.

The 60-Second Interview Pitch

Say this out loud before you type a single line

"I pair a hash map (key -> Node holding value and freq) with a second hash map (freq -> doubly-linked-list bucket of keys at that exact frequency, LRU-ordered). A running min_freq pointer always identifies the lowest occupied bucket. On get or put-on-existing-key, I remove the node from its current bucket, bump freq by 1, and reinsert at the front of the new bucket -- advancing min_freq only if the old bucket just emptied. On put of a brand-new key at capacity, I evict the tail of bucket[min_freq] (the least-recently-used key among the least-frequently-used), insert the new key at frequency 1, and reset min_freq to 1. Every operation is O(1) pointer surgery."

Big-O Invariant Derivation

Complexity & Mathematical Proof

TIME COMPLEXITY

O(1) Average

Look at both get(key) and put(key, value): key_node gives O(1) average lookup of the node holding value and freq. freq_bucket gives O(1) average lookup of the doubly-linked-list bucket for any frequency. Removing a node from its bucket and reinserting at the front of the next bucket (_bump_freq) touches a fixed number of pointer fields, O(1). min_freq is only ever read or incremented by 1, never recomputed by scanning. Eviction pops the tail of bucket[min_freq], also O(1). Every operation is strictly O(1) average time.

SPACE COMPLEXITY

O(C) Auxiliary

Look at memory allocation: the cache holds at most capacity entries, so key_node holds O(C) entries. freq_bucket holds at most O(C) buckets (one per distinct frequency currently present, bounded by C), each bucket's total node count summing to O(C) across all buckets. Total auxiliary space is O(C).

Formal Recurrence Relation

T(get)=O(1),T(put)=O(1)T(\text{get}) = O(1), \quad T(\text{put}) = O(1)T(get)=O(1),T(put)=O(1)

Derivation Progression

Hash Map Direct Node + Bucket Lookup

Tlookup=O(1)T_{\text{lookup}} = O(1)Tlookup​=O(1)

key_node locates the node; freq_bucket locates its frequency's doubly-linked-list bucket, both O(1) average.

Frequency Bump Splice

Tbump=4-6 pointer mutations=O(1)T_{\text{bump}} = 4\text{-}6 \text{ pointer mutations} = O(1)Tbump​=4-6 pointer mutations=O(1)

Removing from bucket[f] and inserting at the front of bucket[f+1] (creating it if absent) is fixed-cost pointer surgery.

min_freq Maintenance

Tmin_freq=O(1)T_{\text{min\_freq}} = O(1)Tmin_freq​=O(1)

min_freq is incremented by exactly 1 only when its own bucket becomes empty, and reset to 1 on a fresh insert -- never recomputed by scanning all buckets.

Variable Definitions

CCC

Maximum cache capacity

QQQ

Total number of get and put operations performed

Memory Architecture & Bounds

🟣 Call Stack

O(1) Non-recursive method calls

🔵 Auxiliary Heap

O(C) key_node map of size C + freq_bucket map whose bucket node counts sum to C

🟢 Output Space

O(1) Scalar return values

Boundary Best / Worst Cases

Best Case

O(1)O(1)O(1) for both get and put operations.

Average Case

O(1)O(1)O(1) standard hash table distribution.

Worst Case

O(1)O(1)O(1) amortized average (O(C)O(C)O(C) in rare catastrophic hash collision degeneration).

Pointer Invariant Transition Progression

Pointer Invariant Transition Progression
Synthesizing vector architecture diagram...
Staff+ Engineering Perspective

Senior SWE Deconstruction & Hardware Caveats

ARCHITECTURAL SIGNALS & INTERVIEW TRIGGERS

Triggers: "LFU Cache", "tie-breaker is least recently used", "O(1) time complexity". Two-level indexing: keys are grouped by frequency, and within the same frequency, ordered by recency. A Senior SWE uses key_to_node map + freq_to_dll map + min_freq integer.

CONSTRAINTS & BOUNDS

Capacity ≤104\le 10^4≤104, up to 2×1052 \times 10^52×105 calls. Strictly O(1)O(1)O(1) per get and put.

FAANG PRODUCTION TRAPS & EDGE CASES

Capacity 0 base case (no-op on put, return -1 on get).

© 2026 Hi👋WebEnterprise. All rights reserved.
Sitemap•llms.txt•