# 문제 설명
- LRU 캐시 알고리즘은 가장 최근에 사용되지 않은 데이터를 먼저 삭제하는 알고리즘이다.
- 캐시 데이터를 딕셔너리로 관리하고, 버퍼에 최근 접근한 데이터 키값을 순서대로 구현한다.
- 배열 0번째에
insert
하는 연산이 시간 소요가 너무 심함.
class LRUCache {
var capacity: Int
var cache: [Int: Int] = [:]
private var buffer: [Int] = []
init(_ capacity: Int) {
self.capacity = capacity
}
func get(_ key: Int) -> Int {
if let value = self.cache[key] {
// 접근 업데이트
if buffer.contains(key) {
buffer.removeAll(where: {$0 == key})
buffer.insert(key, at: 0)
} else {
buffer.insert(key, at: 0)
}
if buffer.count > self.capacity {
let removeKey = buffer.removeLast()
if removeKey != key {
self.cache.removeValue(forKey: removeKey)
}
}
return value
} else {
return -1
}
}
func put(_ key: Int, _ value: Int) {
// 접근 업데이트
if buffer.contains(key) {
buffer.removeAll(where: {$0 == key})
buffer.insert(key, at: 0)
} else {
buffer.insert(key, at: 0)
}
if buffer.count > self.capacity {
let removeKey = buffer.removeLast()
self.cache.removeValue(forKey: removeKey)
}
cache[key] = value
}
}
/**
* Your LRUCache object will be instantiated and called as such:
* let obj = LRUCache(capacity)
* let ret_1: Int = obj.get(key)
* obj.put(key, value)
*/
# 개선 코드
- 양방향 연결리스트로 성능 개선
class ListNode {
var prev: ListNode?
var next: ListNode?
var value = 0
var key = 0
}
class LRUCache {
private var capacity: Int
private var cache: [Int: ListNode] = [:]
private var head: ListNode
private var tail: ListNode
init(_ capacity: Int) {
self.capacity = capacity
head = ListNode()
tail = ListNode()
head.next = tail
tail.prev = head
}
// private func getNode(_ key: Int) -> ListNode?
private func getNode(_ key: Int) -> ListNode? {
guard let node = cache[key] else { return nil }
makeHead(node)
return node
}
// private func makeHead(_ node: ListNode)
private func makeHead(_ node: ListNode) {
node.prev?.next = node.next
node.next?.prev = node.prev
node.next = head.next
node.next?.prev = node
head.next = node
node.prev = head
}
// private func createNode(_ key: Int, _ value: Int)
private func createNode(_ key: Int, _ value: Int) {
let node = ListNode()
node.value = value
node.key = key
cache[key] = node
makeHead(node)
}
func get(_ key: Int) -> Int {
guard let listNode = getNode(key) else { return -1 }
return listNode.value
}
func put(_ key: Int, _ value: Int) {
if let listNode = getNode(key) {
listNode.value = value
return
}
createNode(key, value)
if cache.count > self.capacity, let last = tail.prev {
tail.prev = last.prev
last.prev?.next = tail
cache[last.key] = nil
}
}
}
/**
* Your LRUCache object will be instantiated and called as such:
* let obj = LRUCache(capacity)
* let ret_1: Int = obj.get(key)
* obj.put(key, value)
*/