Leetcode Java LFU Cache
업데이트:
문제
코드
class LFUCache {
private Node head;
private Node tail;
private Map<Integer, Node> map;
private Map<Integer, Node> frequency;
private int capacity;
public LFUCache(int capacity) {
this.head = new Node(-1, -1, -1);
this.tail = new Node(-1, -1, -1);
this.head.next = this.tail;
this.tail.prev = this.head;
this.map = new HashMap<>();
this.frequency = new HashMap<>();
this.capacity = capacity;
}
public int get(int key) {
if (this.map.containsKey(key)) {
Node node = this.map.get(key);
this.update(node);
return node.val;
} else {
return -1;
}
}
public void put(int key, int value) {
if (this.capacity == 0) {
return;
} else if (this.map.containsKey(key)) {
Node node = this.map.get(key);
node.val = value;
this.update(node);
} else {
Node node = new Node(key, value);
if (this.map.size() == this.capacity) {
Node temp = this.head.next;
this.remove(temp);
this.map.remove(temp.key);
}
this.map.put(key, node);
this.insert(this.frequency.getOrDefault(1, this.head), node);
}
}
private void update(Node node) {
Node temp;
if (this.frequency.containsKey(node.count + 1)) {
temp = this.frequency.get(node.count + 1);
} else {
temp = this.frequency.get(node.count);
if (temp == node) {
temp = temp.prev;
}
}
this.remove(node);
node.count++;
this.insert(temp, node);
}
private void remove(Node node) {
if (node.prev.count != node.count && node.count != node.next.count) {
this.frequency.remove(node.count);
} else if (node == frequency.get(node.count)) {
this.frequency.put(node.count, node.prev);
}
Node next = node.next;
Node prev = node.prev;
prev.next = next;
next.prev = prev;
node.next = null;
node.prev = null;
}
private void insert(Node prev, Node curr) {
Node next = prev.next;
next.prev = curr;
curr.next = next;
curr.prev = prev;
prev.next = curr;
this.frequency.put(curr.count, curr);
}
}
class Node {
public Node prev;
public Node next;
public int val;
public int key;
public int count;
public Node(int key, int val) {
this.key = key;
this.val = val;
this.count = 1;
}
public Node(int key, int val, int count) {
this.key = key;
this.val = val;
this.count = count;
}
}
/**
* Your LFUCache object will be instantiated and called as such:
* LFUCache obj = new LFUCache(capacity);
* int param_1 = obj.get(key);
* obj.put(key,value);
*/
결과
설명
- LFU(Least Frequently Used) 캐시의 데이터 구조를 설계하고 구현하는 문제이다.
- 생성자인 LFUCache(int capacity)는 데이터를 담을 한계인 capacity를 이용하여 LFUCache 객체를 초기화한다.
- 메서드인 get(int key)은 key에 해당하는 캐시를 반환한다. 존재하지 않는 경우 -1을 반환한다.
- 메서드인 put(int key, int value)은 key에 해당하는 캐시가 존재하면 value로 수정하고, 존재하지 않는 경우 추가한다.
- 캐시를 추가할 경우, 캐시의 수가 capacity에 도달하면 자주 사용하지 않은 캐시를 제거하고 추가한다.
- 위의 경우 동일한 빈도를 가진 노드가 존재하면 자주 사용하지 않은 캐시를 제거한다.
- 데이터 연결에 필요한 Node 클래스의 전역 변수를 정의한다.
- prev는 이전 노드를 연결하기 위한 변수이다.
- next는 다음 노드를 연결하기 위한 변수이다.
- val은 캐시에 해당하는 값을 저장하기 위한 변수이다.
- key는 캐시에 해당하는 키를 저장하기 위한 변수이다.
- count는 해당 캐시가 발생한 횟수를 저장하기 위한 변수이다.
- 데이터 연결에 필요한 Node 클래스의 생성자를 정의한다.
- key와 val로 Node를 생성하는 경우, count를 1로 초기화한다.
- key와 val, count로 Node를 생성하는 경우, 각 값을 객체에 넣어 초기화한다.
- 문제 풀이에 필요한 변수를 정의한다.
- head와 tail은 노드를 이어줄 경우, 가장 앞과 뒤의 캐시를 노드로 만들어 저장할 변수이다.
- map은 key에 해당하는 캐시를 노드로 저장하기 위한 변수이다.
- frequency는 노드의 발생 빈도 별 캐시를 노드로 저장하기 위한 변수이다.
- 생성자인 LFUCache(int capacity)를 완성한다.
- head와 tail를 key, value, count를 -1로 생성한 Node를 넣어준다.
- head의 next에 tail을, tail의 prev에 head를 넣어 이어준다.
- map과 frequency를 HashMap으로 초기화한다.
- capacity에 주입된 capacity를 넣어준다.
- 캐시의 변경을 위해 update(Node node) 메서드를 정의한다.
- temp 노드를 아래 경우에 따라 넣어준다.
- node의 $count + 1$ 번 발생한 노드가 frequency에 존재하는 경우, temp에 해당 노드를 넣어준다.
- node의 $count + 1$ 번 발생한 노드가 frequency에 존재하지 않는 경우, temp에 node의 count번 발생한 노드를 frequency에서 찾아 넣어주고 temp와 node가 같으면 temp의 prev 노드를 temp에 넣어준다.
- 7번에서 정의한 remove(Node node) 메서드를 이용하여 node를 제거해준다.
- node의 count를 증가시키고, 8번에서 정의한 insert(Node prev, Node curr) 메서드를 temp와 node순으로 넣어 수행한다.
- temp 노드를 아래 경우에 따라 넣어준다.
- 캐시의 삭제를 위해 remove(Node node) 메서드를 정의한다.
- node와 node의 prev와 next count가 모두 다른 경우, frequency에서 node의 count에 해당하는 노드를 삭제한다.
- 위의 경우가 아니고 node가 frequency의 node의 count가 key인 노드와 동일한 경우, frequency 내 node의 count가 key인 값을 node의 prev 노드로 넣어 해당 노드를 끊어준다.
- node의 next 노드와 prev 노드를 각각 정의하여 현재 node를 배제하여 연결시켜준다.
- 캐시의 삽입을 위해 insert(Node prev, Node curr) 메서드를 정의한다.
- prev 자리에 curr 노드를 넣어주고, prev와 curr을 이어준다.
- frequency 내 curr의 count가 키인 노드에 curr을 넣어준다.
- 메서드인 get(int key)을 완성한다.
- map에 key가 키인 노드가 존재하는 경우, 아래를 수행한다.
- map에서 key가 키인 노드를 가져와 해당 노드로 6번에서 정의한 update(Node node) 메서드를 수행하여 캐시 발생 빈도를 증가하여 갱신해준다.
- 위에서 가져온 node의 val 값을 반환한다.
- 위의 경우가 아니면 문제에서 요구한 -1을 반환한다.
- map에 key가 키인 노드가 존재하는 경우, 아래를 수행한다.
- 메서드인 put(int key, int value)을 완성한다.
- capacity가 0인 경우 캐시 저장이 불가능하므로, 아무것도 수행하지 않는다.
- map에 key가 키인 노드가 존재하는 경우, 아래를 수행한다.
- map에서 key가 키인 노드를 가져와 val 값에 value를 넣어준다.
- 위에서 가져온 노드로 6번에서 정의한 update(Node node) 메서드를 수행하여 캐시 발생 빈도와 값을 갱신해준다.
- 그 외의 경우 아래를 수행한다.
- node에 key와 value를 이용한 새 노드를 정의해 넣어준다.
- map의 크기가 capacity와 동일한 경우, head의 next 노드를 7번에서 정의한 remove(Node node) 메서드로 삭제하고 map에서도 해당 key에 해당하는 캐시를 삭제한다.
- map에 key에 해당 하는 키에 node를 넣어준다.
- 8번에서 정의한 insert(Node prev, Node curr) 메서드를 이용하여 frequency에 1번 발생한 캐시의 노드가 있으면 해당 노드를, 없으면 head를 prev자리에 node를 curr 자리에 넣어 수행하여 새 캐시를 이어준다.
소스
Sample Code는 여기에서 확인 가능합니다.
댓글남기기