导航

LeetCode 146. LRU Cache

Posted on 2018-08-30 11:45  隔岸小杨  阅读(207)  评论(0)    收藏  举报

题目链接:https://leetcode.com/problems/lru-cache/description/

Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations: get and put.

get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.
put(key, value) - Set or insert the value if the key is not already present. When the cache reached its capacity, it should invalidate the least recently used item before inserting a new item.

Follow up:
Could you do both operations in O(1) time complexity?

Example:

LRUCache cache = new LRUCache( 2 /* capacity */ );

cache.put(1, 1);
cache.put(2, 2);
cache.get(1);       // returns 1
cache.put(3, 3);    // evicts key 2
cache.get(2);       // returns -1 (not found)
cache.put(4, 4);    // evicts key 1
cache.get(1);       // returns -1 (not found)
cache.get(3);       // returns 3
cache.get(4);       // returns 4
这道题实在是太经典了。之前第一遍做的时候没太当回事,直接使用python自带的OrderDict把问题随便解决了,第二遍做的时候才体会到了这道题的精妙之处。分别考验了你查询时间为O(1)
和插入/移动时间为O(1)的数据结构,which is hashmap and doubly linked list。
具体实现的时候需要自己写一个简化版的Doubly linked list,考虑好把当前node send to tail的各种corner case。其实我的代码实现还是不够简洁,应该可以更granularly的实现,
但实在是懒得再写了。。想了三天已经。。为了debug还自己手动写了dll的打印方法,忽略就好
class Node(object):
    def __init__(self, key, value):
        self.key = key
        self.value = value
        self.prev = None
        self.next = None
class LRUCache(object):

    def __init__(self, capacity):
        """
        :type capacity: int
        """
        self.capacity = capacity
        self.count = 0
        self.hm = {}
        self.head = None
        self.tail = None
        
    def print_llist(self, head):
        while head:
            print "key:" + str(head.key) + "  " + "value:" + str(head.value)
            head = head.next
    
    def _send_tail(self, update_node):
        #print self.hm
        #self.print_llist(self.head)
        if self.tail == update_node:
            return
        if self.head == None and self.tail == None:
            self.head = self.tail = update_node
            return
        if (not update_node.prev) and (not update_node.next):
            self.tail.next = update_node
            update_node.prev = self.tail
            self.tail = update_node
            return
        if self.head == update_node:
            self.head = self.head.next
            self.head.prev = None
            update_node.prev = self.tail
            update_node.next = None
            self.tail.next = update_node
            self.tail = update_node
        else:
            update_node.prev.next = update_node.next
            update_node.next.prev = update_node.prev
            update_node.prev = self.tail
            update_node.next = None
            self.tail.next = update_node
            self.tail = update_node

    def get(self, key):
        """
        :type key: int
        :rtype: int
        """
        #print "get"
        if key in self.hm:
            self._send_tail(self.hm[key])
            return self.hm[key].value
        else:
            return -1


    def put(self, key, value):
        """
        :type key: int
        :type value: int
        :rtype: void
        """
        #print "put"
        if key in self.hm:
            self.hm[key].value = value
            self._send_tail(self.hm[key])
        else:
            new_node = Node(key, value)
            self.hm[key] = new_node
            self._send_tail(new_node)
            if self.count < self.capacity:
                self.count += 1
            else:
                del_key = self.head.key
                self.head = self.head.next
                del self.hm[del_key]
        
        


# Your LRUCache object will be instantiated and called as such:
# obj = LRUCache(capacity)
# param_1 = obj.get(key)
# obj.put(key,value)