학습 노트 | LeetCode 460. LFU 캐 시

LeetCode 460. LFU 캐 시
가장 자주 사용 되 지 않 는 (LFU) 캐 시 알고리즘 을 위해 데이터 구 조 를 설계 하고 구현 하 십시오.다음 동작 을 지원 해 야 합 니 다: get 과 put.
  • get(key) - 키 가 캐 시 에 존재 하면 키 의 값 (항상 정수) 을 가 져 옵 니 다. 그렇지 않 으 면 - 1 을 되 돌려 줍 니 다.
  • put(key, value) - 키 가 존재 하면 값 을 변경 합 니 다.키 가 존재 하지 않 는 다 면 키 쌍 을 삽입 하 십시오.캐 시가 용량 에 도 달 했 을 때 새 항목 을 삽입 하기 전에 가장 자주 사용 하지 않 는 항목 을 무효 로 해 야 합 니 다.이 문제 에서 무승부 (즉, 두 개 이상 의 키 가 같은 사용 주파 수 를 가지 고 있 음) 가 존재 할 때 가장 오래 사용 하지 않 은 키 를 제거 해 야 한다.
  • '항목 의 사용 횟수' 는 이 항목 을 삽입 한 이래 호출 getput 함수 의 횟수 의 합 이다.사용 횟수 는 해당 항목 이 제거 되면 0 으로 설 정 됩 니 다.

  • 진급:
  • O (1) 시간 복잡 도 에서 두 가지 조작 을 수행 할 수 있 습 니까?

  • 예시:
    LFUCache cache = new LFUCache( 2 /* capacity (    ) */ );
    
    cache.put(1, 1);
    cache.put(2, 2);
    cache.get(1);       //    1
    cache.put(3, 3);    //    key 2
    cache.get(2);       //    -1 (   key 2)
    cache.get(3);       //    3
    cache.put(4, 4);    //    key 1
    cache.get(1);       //    -1 (    key 1)
    cache.get(3);       //    3
    cache.get(4);       //    4
    

    코드
    class Node:
        def __init__(self, key, val, freq=1, prev=None, next=None):
            self.key = key
            self.val = val
            self.freq = freq
            self.prev = prev
            self.next = next
    
    class LinkedNodeList:
        def __init__(self):
            self.head = None
            self.tail = None
            self.size = 0
    
        def __len__(self):
            return self.size
    
        def append(self, node):
            if self.head is None and self.tail is None:
                self.head = self.tail = node
            else:
                self.tail.next = node
                node.prev = self.tail
                self.tail = node
            self.size += 1
    
        def remove(self, node):
            assert len(self) >= 1
            if node is self.head and node is self.tail:
                self.head = None
                self.tail = None
            else:
                if node is self.head:
                    self.head = node.next
                    node.next = None
                elif node is self.tail:
                    self.tail = node.prev
                    node.prev = None
                else:
                    prev = node.prev
                    next = node.next
                    
                    prev.next = next
                    next.prev = prev
                    
                    node.prev = None
                    node.next = None
            self.size -= 1
            
    class LFUCache(object):
        def __init__(self, capacity):
            """
            :type capacity: int
            """
            self.heap = []
            self.capacity = capacity
            
            self.cnt = 0
            
            self.freq_mapping = {}
            self.key_mapping = {}        
    
        @property
        def min_freq(self):
            return min(self.freq_mapping.keys())
    
        def _get_existing_node(self, key):
            node = self.key_mapping[key]
            old_freq = node.freq
            new_freq = old_freq + 1
            linked_list = self.freq_mapping[old_freq]
            linked_list.remove(node)
            if len(linked_list) == 0:
                self.freq_mapping.pop(old_freq, None)
            linked_list = self.freq_mapping.get(new_freq, None) or LinkedNodeList()
            node.freq = new_freq
            linked_list.append(node)
            self.freq_mapping[new_freq] = linked_list
            return node
    
        def _put_new_node(self, key, value):
            linked_list = self.freq_mapping.get(1, None) or LinkedNodeList()
            node = Node(key, value)
            self.key_mapping[key] = node
            linked_list.append(node)
            self.freq_mapping[1] = linked_list
            self.cnt += 1        
        
        def get(self, key):
            """
            :type key: int
            :rtype: int
            """
            val = -1
            if key in self.key_mapping:
                node = self._get_existing_node(key)
                val = node.val
            return val        
    
        def put(self, key, value):
            """
            :type key: int
            :type value: int
            :rtype: None
            """
            if self.capacity == 0:
                return
            if key in self.key_mapping:
                node = self._get_existing_node(key)
                node.val = value
            else:
                if self.cnt < self.capacity:
                    self._put_new_node(key, value)
                else:
                    min_freq = self.min_freq
                    linked_list = self.freq_mapping[min_freq]
                    head = linked_list.head
                    self.key_mapping.pop(head.key)
                    linked_list.remove(head)
                    del head
                    if len(linked_list) == 0:
                        self.freq_mapping.pop(min_freq)
                    self._put_new_node(key, value)        
    
    
    
    # Your LFUCache object will be instantiated and called as such:
    # obj = LFUCache(capacity)
    # param_1 = obj.get(key)
    # obj.put(key,value)
    
  • LFU 는 N 개의 사용 주파수 의 양 방향 링크 를 유지 하고 있 으 며, 명중 한 데 이 터 는 free q 가 증가 함 에 따라 더 큰 free q 에 대응 하 는 양 방향 링크 에 다시 배치 되 며, free q 주파수 가 가장 작은 양 방향 링크 는 버퍼 가 초과 되 었 을 때 삭 제 된 데 이 터 를 고려 합 니 다.모든 양 방향 링크 에 대해 새로운 데 이 터 는 항상 append 가 끝 에 있 기 때문에 데 이 터 를 삭제 할 때 최소 주파수 의 양 방향 링크 의 헤더 를 삭제 합 니 다.
  • 좋은 웹페이지 즐겨찾기