Problem


LRU Cache 를 구현하는 문제입니다.

Least Recently Used (LRU) 란 새로운 데이터를 삽입할 때 사용 빈도수가 낮은 데이터부터 삭제하는 캐싱 기법입니다.



Solution

원래 정석대로 구현하자면 Key - Value 를 갖는 Node 클래스를 만들어서 연결 리스트로 구현하면 되지만 Java 에는 LinkedHashMap 이라는 자료구조가 있습니다.

내부적으로 MapLinkedList 를 사용해서 데이터를 넣은 순서를 지켜줍니다.


그리고 이 LinkedHashMap 은 생성자에서 accessOrder 라는 값을 받습니다.

이 값을 true 로 넘겨주면 접근 빈도에 따라서 순서가 바뀌게 됩니다.


예를 들어 아래 코드에서 a, b 순서로 키값을 넣어서 { a=1, b=2 } 순서로 들어있지만, a 에 접근했더니 순서가 바뀝니다.

이처럼 가장 최근에 접근한 값이 연결 리스트의 마지막으로 이동하게 됩니다.

따라서 가장 사용되지 않은 값은 맨 첫번째에 남게 됩니다.

Map<String, String> map = new LinkedHashMap<>(16, 0.75f, true);
map.put("a", "1");
map.put("b", "2"); // {a=1, b=2}
map.get("a");      // {b=2, a=1}
map.forEach((k, v) -> System.out.print(k + ": " + v + ", ")); // b: 2, a: 1

두번째 코드는 LeetCode 에서만 될 것 같은 방법 LinkedHashMap 자체를 상속받아서 구현했습니다.

removeEldestEntry 는 가장 오래된 Entry 를 삭제하기 때문에 좀더 편하게 구현할 수 있습니다.



Java Code

1) LinkedHashMap 을 클래스 내부에 선언해서 구현

class LRUCache {
    private final Map<Integer, Integer> map;
    private final int capacity;

    public LRUCache(int capacity) {
        map = new LinkedHashMap<>(capacity, 0.75f, true);
        this.capacity = capacity;
    }

    public int get(int key) {
        return map.getOrDefault(key, -1);
    }

    public void put(int key, int value) {
        map.put(key, value);

        if (map.size() > capacity) {
            int leastUsedKey = map.keySet().iterator().next();
            map.remove(leastUsedKey);
        }
    }
}

2) LinkedHashMap 을 상속받아서 구현

class LRUCache extends LinkedHashMap<Integer, Integer> {
    private final int capacity;

    public LRUCache(int capacity) {
        super(capacity, 0.75f, true);
        this.capacity = capacity;
    }

    public int get(int key) {
        return super.getOrDefault(key, -1);
    }

    @Override
    protected boolean removeEldestEntry(Map.Entry eldest) {
        return size() > capacity;
    }
}

+ Recent posts