Algorithm
Leet Code Medium
[Swift] LRU Cache
[Swift] LRU Cache
Design a data structure that follows the constraints of a Least Recently Used (LRU) cache.
Implement the LRUCache
class:
LRUCache(int capacity)
Initialize the LRU cache with positive sizecapacity.
int get(int key)
Return the value of the key if the key exists, otherwise return-1
.void put(int key, int value)
Update the value of thekey
if thekey
exists. Otherwise, add thekey-value
pair to the cache. If the number of keys exceeds thecapacity
from this operation, evict the least recently used key.
The functions get
and put
must each run in O(1)
average time complexity.
Example
Input
["LRUCache", "put", "put", "get", "put", "get", "put", "get", "get", "get"]
[[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]
Output
[null, null, null, 1, null, -1, null, -1, 3, 4]
Explanation
LRUCache lRUCache = new LRUCache(2);
lRUCache.put(1, 1); // cache is {1=1}
lRUCache.put(2, 2); // cache is {1=1, 2=2}
lRUCache.get(1); // return 1
lRUCache.put(3, 3); // LRU key was 2, evicts key 2, cache is {1=1, 3=3}
lRUCache.get(2); // returns -1 (not found)
lRUCache.put(4, 4); // LRU key was 1, evicts key 1, cache is {4=4, 3=3}
lRUCache.get(1); // return -1 (not found)
lRUCache.get(3); // return 3
lRUCache.get(4); // return 4
문제 이해
삽입/삭제가 빈번하기 때문에 doubly linked list
자료구조를 가져간다.
중간에 저장된 데이터도 접근해야 하기 때문에 HashMap
을 사용하여 O(1)로 만들어야 한다.
코드
class LRUCache {
class CacheItem {
let key: Int
var value: Int
var prev: CacheItem?
var next: CacheItem?
init(key: Int, value: Int) {
self.key = key
self.value = value
}
}
var head: CacheItem?
var tail: CacheItem?
let capacity: Int
var map: [Int: CacheItem] = [:]
init(_ capacity: Int) {
self.capacity = capacity
}
func get(_ key: Int) -> Int {
guard map.contains(where: { $0.key == key }) else { return -1 }
let current = map[key]
if current !== head {
if current === tail {
// move tail to one in front
tail = tail?.prev
}
// move current to head
if current?.prev != nil {
current?.prev?.next = current?.next
}
if current?.next != nil {
current?.next?.prev = current?.prev
}
current?.next = head
head?.prev = current
current?.prev = nil
head = current
}
return current!.value
}
func put(_ key: Int, _ value: Int) {
if get(key) == -1 {
// insert
let current = CacheItem(key: key, value: value)
if head == nil {
head = current
tail = current
} else {
current.next = head
head?.prev = current
head = current
}
map[key] = current
if let tail = tail, map.count > capacity {
map[tail.key] = nil
tail.prev?.next = nil
self.tail = tail.prev
}
} else {
// update
map[key]?.value = value
}
}
}
풀이
-
다른 분의 멋진 코드
class Node{
var pre: Node?
var next: Node?
var key: Int
var value: Int
init(_ key: Int, _ value: Int){
self.key = key
self.value = value
}
}
class LRUCache {
var capacity: Int
var head: Node?
var tail: Node?
var count: Int
var map: [Int : Node]
init(_ capacity: Int) {
self.capacity = capacity
head = Node(-1, -1)
tail = Node(-1, -1)
head?.next = tail
tail?.pre = head
count = 0
map = [Int: Node]()
}
func moveToHead(_ node: Node?){
node?.next = head?.next
head?.next?.pre = node
node?.pre = head
head?.next = node
}
func deleteNode(_ node: Node?){
node?.next?.pre = node?.pre
node?.pre?.next = node?.next
}
func get(_ key: Int) -> Int {
if(map[key] == nil){
return -1
}
var node = map[key]
deleteNode(node)
moveToHead(node)
return node!.value
}
func put(_ key: Int, _ value: Int) {
if(map[key] != nil){
var node = map[key]
node?.value = value
deleteNode(node)
moveToHead(node)
return
}
var node = Node(key, value)
map[key] = node
if(count == capacity){
var delete = tail?.pre
deleteNode(delete)
map[delete!.key] = nil
count -= 1
}
moveToHead(node)
count+=1
}
}
잘 배웠습니다.
-
댓글남기기