我是靠谱客的博主 鳗鱼世界,最近开发中收集的这篇文章主要介绍leetcode专题训练146. LRU Cache,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

解法1:
解法1我是当作大模拟来做的。由于key如果被用,那么无论之前在什么位置,都要被换到最新使用的位置。所以一直在想什么数据结构可以灵活换位置,后来发现可以用链表,所以维护了一个链表,链表中的顺序由最远使用到最近使用。而且由于需要把最远使用的弹出,把最新使用的插入,所以链表的头和尾都需要有个指针指示。在本代码中,分别使用cache_head和cache_tail表示。而取键值的操作,为了不每次都从链表头遍历,我使用了一个dict数据结构,这个数据结构单纯的用于存储LRU中的键值,取值的复杂度为O(1),由于要和链表中节点同步删除,所以还要在容量超过capacity时,删除字典中元素,复杂度为O(n)。
数据结构说完了,具体操作看代码中注释即可。

class Node:
    def __init__(self, key, left=None, right=None):
        self.key = key
        self.right = right

class LRUCache:

    def __init__(self, capacity: int):
    	# 若capacity非正数,那assert退出
        assert capacity > 0
        self.capacity = capacity
        self.cache_head = Node(0) # 链表头,空头
        self.cache_tail = self.cache_head # 链表尾
        self.now_len = 0 # 当前链表长度
        self.cache = {} # 存储key和value的dict

    def get(self, key: int) -> int:
        # 如果该值不存在于cache中,返回-1
        if key not in self.cache.keys():
            return -1
        else:
            # print("-----get-------")
            # 将p挪到链表最后,代表最近使用
            p = self.cache_head.right
            pre = self.cache_head
            while p is not None:
                if p.key == key:
                    # 已经是最常使用的了,不用再换位置了
                    if p.right is None:
                        break
                    pre.right = p.right
                    self.cache_tail.right = p
                    p.right = None
                    self.cache_tail = p
                    break
                p = p.right
                pre = pre.right

            # p = self.cache_head.right
            # while p is not None:
            #     print(p.key, " ", self.cache[p.key])
            #     p = p.right
            # print("-----end get-------")

            return self.cache[key]

    def put(self, key: int, value: int) -> None:
        # print("-----put-------")
        if self.get(key) == -1:
            # 表已满,则删除最远使用节点
            if self.now_len == self.capacity:
                p = self.cache_head.right
                self.cache_head.right = p.right
                # print(p.right.key)
                # 删除字典中最不常用
                self.cache.pop(p.key)
                # 删除链表中节点
                del p
                self.now_len -= 1
            p = Node(key)
            self.cache_tail.right = p
            self.cache_tail = p
            self.now_len += 1

        # 顺序已经在self.get这个步骤中调整过了,所以此处只用赋值就行了
        self.cache[key] = value

        # p = self.cache_head.right
        # while p is not None:
        #     print(p.key, " ", self.cache[p.key])
        #     p = p.right
        # print("-----end put-------")

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

解法2:
看了题解,发现题解用了双向链表,同时dict中存储的是key和双向链表中节点的对应,而不是key和value的对应,且由于是双向链表,所以可以很好的将节点取出并搁到最后,非常巧妙。
在处理当前节点p的时候,由于是双向链表,p.left.right和p.right.left均要处理,一个都不能落下。

class Node:
    def __init__(self, key, value, left=None, right=None):
        self.key = key
        self.value = value
        self.left = left
        self.right = right

class LRUCache:

    def __init__(self, capacity: int):
        assert capacity > 0
        self.capacity = capacity
        self.cache_head = Node(0, 0)
        self.cache_tail = self.cache_head
        self.now_len = 0
        self.cache = {}

    def get(self, key: int) -> int:
        # 如果该值不存在于cache中,返回-1
        if key not in self.cache.keys():
            return -1
        else:
            p = self.cache[key]

            # 已经是最常使用的了,不用再换位置了
            if p.right is None:
                return p.value

            # 将p挪到最后,代表最近使用
            p1 = p.left
            p.left.right = p.right
            p.right.left = p.left
            p.left = self.cache_tail
            p2 = p.right
            self.cache_tail.right = p
            p.right = None
            self.cache_tail = p

            return p.value

    def put(self, key: int, value: int) -> None:
        if self.get(key) == -1:
            # 表已满,则删除最远使用节点
            if self.now_len == self.capacity:
                p = self.cache_head.right
                self.cache_head.right = p.right
                if p.right is not None:
                    p.right.left = self.cache_head
                # 删除字典中最不常用
                self.cache.pop(p.key)
                # 删除链表中节点
                del p
                self.now_len -= 1
            p = Node(key, value, left=self.cache_tail)
            self.cache_tail.right = p
            self.cache_tail = p
            self.now_len += 1
            self.cache[key] = p
        else:
            # 顺序已经在self.get这个步骤中调整过了,所以此处只用赋值就行了
            self.cache_tail.value = value

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

最后

以上就是鳗鱼世界为你收集整理的leetcode专题训练146. LRU Cache的全部内容,希望文章能够帮你解决leetcode专题训练146. LRU Cache所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(40)

评论列表共有 0 条评论

立即
投稿
返回
顶部