|
| 1 | +% #Medium #Top_100_Liked_Questions #Top_Interview_Questions #Hash_Table #Design #Linked_List |
| 2 | +% #Doubly_Linked_List #Udemy_Linked_List #Big_O_Time_O(1)_Space_O(capacity) |
| 3 | +% #2025_01_18_Time_312_(100.00%)_Space_273.78_(100.00%) |
| 4 | + |
| 5 | +%% Persistent Term Keys |
| 6 | +-define(CAPACITY_KEY, {lru_cache, capacity}). |
| 7 | +-define(CACHE_TABLE, lru_cache_cache_table). |
| 8 | +-define(TTL_TABLE, lru_cache_ttl_table). |
| 9 | + |
| 10 | +%% API Specifications |
| 11 | +-spec lru_cache_init_(Capacity :: integer()) -> ok. |
| 12 | +lru_cache_init_(Capacity) -> |
| 13 | + persistent_term:put(?CAPACITY_KEY, Capacity), |
| 14 | + case ets:info(?CACHE_TABLE) of |
| 15 | + undefined -> |
| 16 | + ets:new(?CACHE_TABLE, [set, public, named_table]), |
| 17 | + ets:new(?TTL_TABLE, [ordered_set, public, named_table]); |
| 18 | + _ -> |
| 19 | + ets:delete_all_objects(?CACHE_TABLE), |
| 20 | + ets:delete_all_objects(?TTL_TABLE) |
| 21 | + end, |
| 22 | + ok. |
| 23 | + |
| 24 | +-spec lru_cache_get(Key :: integer()) -> integer(). |
| 25 | +lru_cache_get(Key) -> |
| 26 | + case extract(Key) of |
| 27 | + {Key, Value} -> |
| 28 | + insert(Key, Value), |
| 29 | + Value; |
| 30 | + -1 -> |
| 31 | + -1 |
| 32 | + end. |
| 33 | + |
| 34 | +-spec lru_cache_put(Key :: integer(), Value :: integer()) -> ok. |
| 35 | +lru_cache_put(Key, Value) -> |
| 36 | + _ = extract(Key), |
| 37 | + insert(Key, Value), |
| 38 | + evict(), |
| 39 | + ok. |
| 40 | + |
| 41 | +%% Internal Functions |
| 42 | +extract(Key) -> |
| 43 | + case ets:lookup(?CACHE_TABLE, Key) of |
| 44 | + [{Key, Uniq, Value}] -> |
| 45 | + ets:delete(?TTL_TABLE, Uniq), |
| 46 | + {Key, Value}; |
| 47 | + [] -> |
| 48 | + -1 |
| 49 | + end. |
| 50 | + |
| 51 | +insert(Key, Value) -> |
| 52 | + Uniq = unique_integer(), |
| 53 | + ets:insert(?CACHE_TABLE, {Key, Uniq, Value}), |
| 54 | + ets:insert(?TTL_TABLE, {Uniq, Key}). |
| 55 | + |
| 56 | +evict() -> |
| 57 | + Capacity = persistent_term:get(?CAPACITY_KEY), |
| 58 | + CurrentSize = ets:info(?CACHE_TABLE, size), |
| 59 | + if |
| 60 | + CurrentSize > Capacity -> |
| 61 | + Uniq = ets:first(?TTL_TABLE), |
| 62 | + [{_, Key}] = ets:lookup(?TTL_TABLE, Uniq), |
| 63 | + ets:delete(?TTL_TABLE, Uniq), |
| 64 | + ets:delete(?CACHE_TABLE, Key); |
| 65 | + true -> |
| 66 | + ok |
| 67 | + end. |
| 68 | + |
| 69 | +unique_integer() -> |
| 70 | + erlang:unique_integer([monotonic]). |
| 71 | + |
| 72 | +%% Your functions will be called as such: |
| 73 | +%% lru_cache_init_(Capacity), |
| 74 | +%% Param_1 = lru_cache_get(Key), |
| 75 | +%% lru_cache_put(Key, Value), |
| 76 | + |
| 77 | +%% lru_cache_init_ will be called before every test case, in which you can do some necessary initializations. |
0 commit comments