← Bytedance Interview Insights
The part I fumbled initially was the tie-breaking.
Use a combination of a hash map for O(1) key lookup and a doubly linked list of frequency buckets, where each bucket contains a doubly linked list of keys with the same frequency. On get or put, update the key's frequency and move it to the appropriate bucket, maintaining O(1) operations. On eviction, remove the least frequently used key from the lowest frequency bucket, breaking ties by removing the least recently used key (the tail of that bucket's list).
Pro tip: Mention that you can optimize by using a min-frequency pointer to avoid scanning buckets, and discuss how to handle edge cases like updating an existing key or capacity zero. Also, briefly compare with LRU cache to show deeper understanding.
Confirm that get and put must be O(1) average time, eviction policy is LFU with LRU tie-breaking, and discuss edge cases like capacity 0 or 1, and updating existing keys.
Propose a hash map mapping keys to nodes, and a doubly linked list of frequency buckets. Each bucket contains a doubly linked list of keys with that frequency, ordered by recency (most recent at head).
If key exists, retrieve its node, increment its frequency, and move it to the next frequency bucket (creating one if needed). Return the value. If not, return -1.
If key exists, update value and increment frequency similarly to get. If new, insert with frequency 1. If capacity exceeded, evict the least frequently used key (from the lowest frequency bucket, tail for LRU tie-break).
Explain why operations are O(1) average: hash map provides O(1) access, and bucket movements involve constant number of pointer updates. Discuss handling of capacity 0 and updating existing keys.
AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.