Design and implement a data structure for a Least Frequently Used (LFU) cache.
Implement the LFUCache class:
LFUCache(int capacity) Initializes the object with the capacity of the data structure.
int get(int key) Gets the value of the key if the key exists in the cache. Otherwise, returns -1.
void put(int key, int value) Update the value of the key if present, or inserts the key if not already present. When the cache reaches its capacity, it should invalidate and remove the least frequently used key before inserting a new item.
For this problem, when there is a tie (i.e., two or more keys with the same frequency), the least recently used key would be invalidated.
To determine the least frequently used key, a use counter is maintained for each key in the cache. The key with the smallest use counter is the least frequently used key.
When a key is first inserted into the cache, its use counter is set to 1 (due to the put operation). The use counter for a key in the cache is incremented either a get or put operation is called on it.
The functions get and put must each run in O(1) average time complexity.
The key insight is to use frequency buckets with doubly-linked lists for O(1) operations. Best approach uses hash maps to store key-node mappings and frequency-list mappings, allowing constant-time get/put operations. Time: O(1), Space: O(n)
Common Approaches
✓
Brute Force with Linear Search
⏱️ Time: O(n)
Space: O(n)
Keep all cache items in a simple list with frequency counters. When cache is full, scan entire list to find the item with minimum frequency (and least recently used among ties).
Frequency Buckets with Doubly-Linked Lists
⏱️ Time: O(1)
Space: O(n)
Use hash map to store key-value pairs and another hash map to group keys by frequency. Each frequency bucket contains a doubly-linked list for O(1) insertion/deletion. Track minimum frequency for quick eviction.
Brute Force with Linear Search — Algorithm Steps
Store items in array with frequency counters
On get/put: update frequency and last used time
On eviction: scan all items to find minimum frequency
Visualization
Tap to expand
Step-by-Step Walkthrough
1
Store Items
Keep cache items with frequency counters
2
Update Frequency
Increment counter on each access
3
Linear Search
Scan all items to find minimum frequency
Code -
solution.c — C
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
/* ─────────────────────────────────────────────
Hash-map entry (open-addressing, linear probe)
───────────────────────────────────────────── */
#define TABLE_SIZE 1024
typedef struct {
int key;
int value;
int used; /* 1 = occupied, 0 = empty, -1 = deleted */
} Entry;
typedef struct {
Entry slots[TABLE_SIZE];
} HashMap;
static void hm_init(HashMap *m) {
memset(m->slots, 0, sizeof(m->slots));
}
static int hm_idx(int key) {
return ((key % TABLE_SIZE) + TABLE_SIZE) % TABLE_SIZE;
}
/* returns 1 on success, 0 if not found */
static int hm_get(const HashMap *m, int key, int *out_val) {
int idx = hm_idx(key);
for (int i = 0; i < TABLE_SIZE; i++) {
int pos = (idx + i) % TABLE_SIZE;
if (m->slots[pos].used == 0) return 0;
if (m->slots[pos].used == 1 && m->slots[pos].key == key) {
*out_val = m->slots[pos].value;
return 1;
}
}
return 0;
}
static void hm_put(HashMap *m, int key, int value) {
int idx = hm_idx(key);
for (int i = 0; i < TABLE_SIZE; i++) {
int pos = (idx + i) % TABLE_SIZE;
if (m->slots[pos].used != 1 || m->slots[pos].key == key) {
m->slots[pos].key = key;
m->slots[pos].value = value;
m->slots[pos].used = 1;
return;
}
}
}
static void hm_erase(HashMap *m, int key) {
int idx = hm_idx(key);
for (int i = 0; i < TABLE_SIZE; i++) {
int pos = (idx + i) % TABLE_SIZE;
if (m->slots[pos].used == 0) return;
if (m->slots[pos].used == 1 && m->slots[pos].key == key) {
m->slots[pos].used = -1; /* tombstone */
return;
}
}
}
/* iterate over all live entries */
static int hm_iter(const HashMap *m, int start, int *out_key, int *out_val) {
for (int i = start; i < TABLE_SIZE; i++) {
if (m->slots[i].used == 1) {
*out_key = m->slots[i].key;
*out_val = m->slots[i].value;
return i + 1;
}
}
return -1;
}
/* ─────────────────────────────────────────────
LFU Cache
───────────────────────────────────────────── */
typedef struct {
int capacity;
int current_time;
HashMap cache; /* key -> value */
HashMap freq; /* key -> frequency */
HashMap time_map; /* key -> last access time */
} LFUCache;
LFUCache* lfucache_create(int capacity) {
LFUCache *c = (LFUCache *)malloc(sizeof(LFUCache));
c->capacity = capacity;
c->current_time = 0;
hm_init(&c->cache);
hm_init(&c->freq);
hm_init(&c->time_map);
return c;
}
void lfucache_free(LFUCache *c) {
free(c);
}
int lfucache_get(LFUCache *c, int key) {
c->current_time++;
int val;
if (!hm_get(&c->cache, key, &val)) return -1;
int f; hm_get(&c->freq, key, &f);
hm_put(&c->freq, key, f + 1);
hm_put(&c->time_map, key, c->current_time);
return val;
}
void lfucache_put(LFUCache *c, int key, int value) {
c->current_time++;
if (c->capacity == 0) return;
int existing;
if (hm_get(&c->cache, key, &existing)) {
/* Update existing key */
hm_put(&c->cache, key, value);
int f; hm_get(&c->freq, key, &f);
hm_put(&c->freq, key, f + 1);
hm_put(&c->time_map, key, c->current_time);
} else {
/* Count current size */
int size = 0;
int k, v, s = 0;
while ((s = hm_iter(&c->cache, s, &k, &v)) != -1) size++;
if (size >= c->capacity) {
/* Find minimum frequency */
int min_freq = INT_MAX;
s = 0;
while ((s = hm_iter(&c->freq, s, &k, &v)) != -1)
if (v < min_freq) min_freq = v;
/* Among LFU keys, find LRU (smallest time) */
int lru_key = -1;
int min_time = INT_MAX;
s = 0;
while ((s = hm_iter(&c->freq, s, &k, &v)) != -1) {
if (v == min_freq) {
int t; hm_get(&c->time_map, k, &t);
if (t < min_time) { min_time = t; lru_key = k; }
}
}
/* Evict */
hm_erase(&c->cache, lru_key);
hm_erase(&c->freq, lru_key);
hm_erase(&c->time_map, lru_key);
}
/* Insert new key */
hm_put(&c->cache, key, value);
hm_put(&c->freq, key, 1);
hm_put(&c->time_map, key, c->current_time);
}
}
/* ─────────────────────────────────────────────
Input parsing helpers
───────────────────────────────────────────── */
#define MAX_OPS 500
#define MAX_ARGS 4
typedef struct {
char name[32];
int args[MAX_ARGS];
int argc;
} Op;
static int parse_operations(const char *line, Op ops[], int max_ops) {
int count = 0;
const char *p = line;
while (*p && count < max_ops) {
while (*p && *p != '"') p++;
if (!*p) break;
p++;
int i = 0;
while (*p && *p != '"' && i < 31)
ops[count].name[i++] = *p++;
ops[count].name[i] = '\0';
ops[count].argc = 0;
count++;
if (*p == '"') p++;
}
return count;
}
static void parse_values(const char *line, Op ops[], int n) {
const char *p = line;
if (*p == '[') p++; /* skip outer '[' */
for (int op_idx = 0; op_idx < n; op_idx++) {
ops[op_idx].argc = 0;
while (*p && *p != '[') p++;
if (!*p) break;
p++;
while (*p && *p != ']') {
while (*p == ' ' || *p == ',') p++;
if (*p == ']') break;
int neg = 0;
if (*p == '-') { neg = 1; p++; }
if (*p < '0' || *p > '9') { p++; continue; }
int num = 0;
while (*p >= '0' && *p <= '9') { num = num*10 + (*p - '0'); p++; }
ops[op_idx].args[ops[op_idx].argc++] = neg ? -num : num;
}
if (*p == ']') p++;
}
}
/* ─────────────────────────────────────────────
main
───────────────────────────────────────────── */
int main(void) {
char operations_line[4096];
char values_line[4096];
if (!fgets(operations_line, sizeof(operations_line), stdin)) return 1;
if (!fgets(values_line, sizeof(values_line), stdin)) return 1;
operations_line[strcspn(operations_line, "\n")] = '\0';
values_line [strcspn(values_line, "\n")] = '\0';
Op ops[MAX_OPS];
int n = parse_operations(operations_line, ops, MAX_OPS);
parse_values(values_line, ops, n);
LFUCache *cache = NULL;
char results[MAX_OPS][32];
for (int i = 0; i < n; i++) {
if (strcmp(ops[i].name, "LFUCache") == 0) {
if (cache) lfucache_free(cache);
cache = lfucache_create(ops[i].args[0]);
strcpy(results[i], "null");
} else if (strcmp(ops[i].name, "get") == 0) {
int r = lfucache_get(cache, ops[i].args[0]);
sprintf(results[i], "%d", r);
} else if (strcmp(ops[i].name, "put") == 0) {
lfucache_put(cache, ops[i].args[0], ops[i].args[1]);
strcpy(results[i], "null");
}
}
printf("[");
for (int i = 0; i < n; i++) {
if (i > 0) printf(",");
printf("%s", results[i]);
}
printf("]\n");
if (cache) lfucache_free(cache);
return 0;
}
Time & Space Complexity
Time Complexity
⏱️
O(n)
Each eviction requires scanning all n items to find minimum frequency
n
2n
✓ Linear Growth
Space Complexity
O(n)
Store up to n cache items with their metadata
n
2n
⚡ Linearithmic Space
180.0K Views
HighFrequency
~35 minAvg. Time
4.2K Likes
Ln 1, Col 1
Smart Actions
💡Explanation
AI Ready
💡 SuggestionTabto acceptEscto dismiss
// Output will appear here after running code
Code Editor Closed
Click the red button to reopen
Algorithm Visualization
Pinch to zoom • Tap outside to close
Test Cases
0 passed
0 failed
3 pending
Select Compiler
Choose a programming language
Compiler list would appear here...
AI Editor Features
Header Buttons
💡
Explain
Get a detailed explanation of your code. Select specific code or analyze the entire file. Understand algorithms, logic flow, and complexity.
🔧
Fix
Automatically detect and fix issues in your code. Finds bugs, syntax errors, and common mistakes. Shows you what was fixed.
💡
Suggest
Get improvement suggestions for your code. Best practices, performance tips, and code quality recommendations.
💬
Ask AI
Open an AI chat assistant to ask any coding questions. Have a conversation about your code, get help with debugging, or learn new concepts.
Smart Actions (Slash Commands)
🔧
/fix Enter
Find and fix issues in your code. Detects common problems and applies automatic fixes.
💡
/explain Enter
Get a detailed explanation of what your code does, including time/space complexity analysis.
🧪
/tests Enter
Automatically generate unit tests for your code. Creates comprehensive test cases.
📝
/docs Enter
Generate documentation for your code. Creates docstrings, JSDoc comments, and type hints.
⚡
/optimize Enter
Get performance optimization suggestions. Improve speed and reduce memory usage.
AI Code Completion (Copilot-style)
👻
Ghost Text Suggestions
As you type, AI suggests code completions shown in gray text. Works with keywords like def, for, if, etc.
Tabto acceptEscto dismiss
💬
Comment-to-Code
Write a comment describing what you want, and AI generates the code. Try: # two sum, # binary search, # fibonacci
💡
Pro Tip: Select specific code before using Explain, Fix, or Smart Actions to analyze only that portion. Otherwise, the entire file will be analyzed.