边工作边刷题:70天一遍leetcode: day 98

LRU Cache

这是一道leetcode的难题,这种题往往是算法结构很复杂,涉及一个或多个考点算法和数据结构的组合,同时又有很多corner cases要考虑。所以一定要找到合适memorize的结构,这样很容易推导出整个题目的解。否则会不断的记了忘忘了记。

这题分成大面上有两个考点,一个是LRU算法本身,另一个是hash table和doubly list的操作。LRU算法围绕两个接口get() and put()。这题的internal data structure之所以是hash table和list的结合是因为接口支持基于key的操作,而进出则是基于顺序,所以hash table用来支持key query,而list可以跟踪访问顺序。用到doubly list是因为其支持list上单node的reference的所有操作,不需要同时保存prev或者next的reference。
high-level操作

  • get():从hash table查询key value返回值,同时移动key对应的node到队列头
  • put():考虑两种情况:key已经在cache中存在或者不存在。
    • 如果存在,与get的操作类似。
    • 如果不存在,因为LRU cache的capacity有限,进一步考虑是否当前cache中的key已经等于当前capacity
      • 如果等于,需要删除list的最后node,然后插入新的到hash table和队头
      • 如果小于,直接插入新的到hash table和队头

low-level细节

  • 根据high-level算法,无论是更新存在的key或者加入新key,对list只有两个基本操作removeNode()和addNodeToHead(),核心都是更新prev和next reference。无论是删除还是添加,都有可能对队头node,所以需要一个dummy node作为sentinel head
  • corner cases:对于删除操作,一般的操作是更新next node的prev,所以对于tail,其next node为null,需要忽略这步。类似,对于添加到队头操作,需要更新当前队头node的prev,所以如果是空list,也要忽略这步。
class LRUCache(object):
    class ListNode(object):
        def __init__(self, key, val):
            self.key = key
            self.val = val
            self.next = None
            self.prev = None
    
    def __init__(self, capacity):
        """
        :type capacity: int
        """
        self.capacity = capacity
        self.size = 0
        self.hmap = {}
        self.dummy = self.ListNode(0,0)
        self.tail = self.dummy

    def get(self, key):
        """
        :rtype: int
        """
        hmap=self.hmap
        if key not in hmap:
            return -1
            
        val = hmap[key].val
        self.deleteNode(hmap[key])
        self.addNode(hmap[key])
        return val

    def set(self, key, value):
        """
        :type key: int
        :type value: int
        :rtype: nothing
        """
        hmap=self.hmap
        if key not in hmap:
            print self.size,self.capacity
            if self.size==self.capacity:
                print self.tail.key
                hmap.pop(self.tail.key)
                self.deleteNode(self.tail)
                self.size-=1
            hmap[key]=self.ListNode(key,value)
            self.addNode(hmap[key])
            self.size+=1
        else:
            hmap[key].val=value
            self.deleteNode(hmap[key])
            self.addNode(hmap[key])
        
    def deleteNode(self, node):
        # print self.hmap, node.val, self.tail.val
        if self.tail==node:
            self.tail = self.tail.prev
            self.tail.next = None
        else:
            node.prev.next = node.next
            node.next.prev = node.prev
        
    def addNode(self, node):
        dummy = self.dummy
        if dummy.next:
            dummy.next.prev = node
        else:
            self.tail = node
        node.prev = dummy
        node.next = dummy.next
        dummy.next = node
posted @ 2016-03-26 07:05  absolute100  阅读(125)  评论(0编辑  收藏  举报