LeetCode #2622 — MEDIUM

Cache With Time Limit

Move from brute-force thinking to an efficient approach using core interview patterns strategy.

Solve on LeetCode
The Problem

Problem Statement

Write a class that allows getting and setting key-value pairs, however a time until expiration is associated with each key.

The class has three public methods:

set(key, value, duration): accepts an integer key, an integer value, and a duration in milliseconds. Once the duration has elapsed, the key should be inaccessible. The method should return true if the same un-expired key already exists and false otherwise. Both the value and duration should be overwritten if the key already exists.

get(key): if an un-expired key exists, it should return the associated value. Otherwise it should return -1.

count(): returns the count of un-expired keys.

Example 1:

Input: 
actions = ["TimeLimitedCache", "set", "get", "count", "get"]
values = [[], [1, 42, 100], [1], [], [1]]
timeDelays = [0, 0, 50, 50, 150]
Output: [null, false, 42, 1, -1]
Explanation:
At t=0, the cache is constructed.
At t=0, a key-value pair (1: 42) is added with a time limit of 100ms. The value doesn't exist so false is returned.
At t=50, key=1 is requested and the value of 42 is returned.
At t=50, count() is called and there is one active key in the cache.
At t=100, key=1 expires.
At t=150, get(1) is called but -1 is returned because the cache is empty.

Example 2:

Input: 
actions = ["TimeLimitedCache", "set", "set", "get", "get", "get", "count"]
values = [[], [1, 42, 50], [1, 50, 100], [1], [1], [1], []]
timeDelays = [0, 0, 40, 50, 120, 200, 250]
Output: [null, false, true, 50, 50, -1, 0]
Explanation:
At t=0, the cache is constructed.
At t=0, a key-value pair (1: 42) is added with a time limit of 50ms. The value doesn't exist so false is returned.
At t=40, a key-value pair (1: 50) is added with a time limit of 100ms. A non-expired value already existed so true is returned and the old value was overwritten.
At t=50, get(1) is called which returned 50.
At t=120, get(1) is called which returned 50.
At t=140, key=1 expires.
At t=200, get(1) is called but the cache is empty so -1 is returned.
At t=250, count() returns 0 because the cache is empty.

Constraints:

  • 0 <= key, value <= 109
  • 0 <= duration <= 1000
  • 1 <= actions.length <= 100
  • actions.length === values.length
  • actions.length === timeDelays.length
  • 0 <= timeDelays[i] <= 1450
  • actions[i] is one of "TimeLimitedCache", "set", "get" and "count"
  • First action is always "TimeLimitedCache" and must be executed immediately, with a 0-millisecond delay

Roadmap

  1. Brute Force Baseline
  2. Core Insight
  3. Algorithm Walkthrough
  4. Edge Cases
  5. Full Annotated Code
  6. Interactive Study Demo
  7. Complexity Analysis
Step 01

Brute Force Baseline

Problem summary: Write a class that allows getting and setting key-value pairs, however a time until expiration is associated with each key. The class has three public methods: set(key, value, duration): accepts an integer key, an integer value, and a duration in milliseconds. Once the duration has elapsed, the key should be inaccessible. The method should return true if the same un-expired key already exists and false otherwise. Both the value and duration should be overwritten if the key already exists. get(key): if an un-expired key exists, it should return the associated value. Otherwise it should return -1. count(): returns the count of un-expired keys.

Baseline thinking

Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.

Pattern signal: General problem-solving

Example 1

["TimeLimitedCache", "set", "get", "count", "get"]
[[], [1, 42, 100], [1], [], [1]]
[0, 0, 50, 50, 150]

Example 2

["TimeLimitedCache", "set", "set", "get", "get", "get", "count"]
[[], [1, 42, 50], [1, 50, 100], [1], [1], [1], []]
[0, 0, 40, 50, 120, 200, 250]

Related Problems

  • Debounce (debounce)
  • Promise Time Limit (promise-time-limit)
  • Promise Pool (promise-pool)
Step 02

Core Insight

What unlocks the optimal approach

  • You can delay execution of code with "ref = setTimeout(fn, delay)". You can abort the execution with "clearTimeout(ref)"
  • When storing the values in the cache, also store a reference to the timeout. The timeout should clear the key from the cache after the expiration has elapsed.
  • When you set a key that already exists, clear the existing timeout.
Interview move: turn each hint into an invariant you can check after every iteration/recursion step.
Step 03

Algorithm Walkthrough

Iteration Checklist

  1. Define state (indices, window, stack, map, DP cell, or recursion frame).
  2. Apply one transition step and update the invariant.
  3. Record answer candidate when condition is met.
  4. Continue until all input is consumed.
Use the first example testcase as your mental trace to verify each transition.
Step 04

Edge Cases

Minimum Input
Single element / shortest valid input
Validate boundary behavior before entering the main loop or recursion.
Duplicates & Repeats
Repeated values / repeated states
Decide whether duplicates should be merged, skipped, or counted explicitly.
Extreme Constraints
Upper-end input sizes
Re-check complexity target against constraints to avoid time-limit issues.
Invalid / Corner Shape
Empty collections, zeros, or disconnected structures
Handle special-case structure before the core algorithm path.
Step 05

Full Annotated Code

Source-backed implementations are provided below for direct study and interview prep.

// Accepted solution for LeetCode #2622: Cache With Time Limit
// Auto-generated Java example from ts.
class Solution {
    public void exampleSolution() {
    }
}
// Reference (ts):
// // Accepted solution for LeetCode #2622: Cache With Time Limit
// class TimeLimitedCache {
//     #cache: Map<number, [value: number, expire: number]> = new Map();
// 
//     set(key: number, value: number, duration: number): boolean {
//         const isExist = this.#cache.has(key);
// 
//         if (!this.#isExpired(key)) {
//             this.#cache.set(key, [value, Date.now() + duration]);
//         }
// 
//         return isExist;
//     }
// 
//     get(key: number): number {
//         if (this.#isExpired(key)) return -1;
//         const res = this.#cache.get(key)?.[0] ?? -1;
//         return res;
//     }
// 
//     count(): number {
//         const xs = Array.from(this.#cache).filter(([key]) => !this.#isExpired(key));
//         return xs.length;
//     }
// 
//     #isExpired = (key: number) =>
//         this.#cache.has(key) &&
//         (this.#cache.get(key)?.[1] ?? Number.NEGATIVE_INFINITY) < Date.now();
// }
// 
// /**
//  * Your TimeLimitedCache object will be instantiated and called as such:
//  * var obj = new TimeLimitedCache()
//  * obj.set(1, 42, 1000); // false
//  * obj.get(1) // 42
//  * obj.count() // 1
//  */
Step 06

Interactive Study Demo

Use this to step through a reusable interview workflow for this problem.

Press Step or Run All to begin.
Step 07

Complexity Analysis

Time
O(n)
Space
O(1)

Approach Breakdown

BRUTE FORCE
O(n²) time
O(1) space

Two nested loops check every pair or subarray. The outer loop fixes a starting point, the inner loop extends or searches. For n elements this gives up to n²/2 operations. No extra space, but the quadratic time is prohibitive for large inputs.

OPTIMIZED
O(n) time
O(1) space

Most array problems have an O(n²) brute force (nested loops) and an O(n) optimal (single pass with clever state tracking). The key is identifying what information to maintain as you scan: a running max, a prefix sum, a hash map of seen values, or two pointers.

Shortcut: If you are using nested loops on an array, there is almost always an O(n) solution. Look for the right auxiliary state.
Coach Notes

Common Mistakes

Review these before coding to avoid predictable interview regressions.

Off-by-one on range boundaries

Wrong move: Loop endpoints miss first/last candidate.

Usually fails on: Fails on minimal arrays and exact-boundary answers.

Fix: Re-derive loops from inclusive/exclusive ranges before coding.