[leetcode] 146. LRU Cache

284 篇文章 0 订阅
11 篇文章 1 订阅

感想

这道题在leetcode是hard的难度,通过率只有21.2%,我记得在某次笔试的时候做到了这一道题,那时候做得不怎么好,我这里把记录一下我以前写的代码,就当复习一下

题目

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

代码

class LRUCache {
private:
    list<pair<int,int>> cache;
    int size;
    unordered_map<int,list<pair<int,int>>::iterator> hash;
public:
    LRUCache(int capacity) {
        size=capacity;
    }
    
    int get(int key) {
        auto it=hash.find(key);
        if(it==hash.end()) return -1;
        cache.splice(cache.begin(),cache,it->second);
        return it->second->second;
    }
    
    void put(int key, int value) {
        auto it=hash.find(key);
        if(it!=hash.end()){
            it->second->second=value;
            cache.splice(cache.begin(),cache,it->second);
            return;
        }
        cache.insert(cache.begin(),make_pair(key,value));
        hash[key]=cache.begin();
        if(cache.size()>size){
            hash.erase(cache.back().first);
            cache.pop_back();
        }
    }
};

/**
 * Your LRUCache object will be instantiated and called as such:
 * LRUCache obj = new LRUCache(capacity);
 * int param_1 = obj.get(key);
 * obj.put(key,value);
 */

analysis

如果来了一个get请求, 我们仍然先去查hash表, 如果key存在hash表中, 那么需要将这个结点在链表的中的位置移动到链表首部.否则返回-1.

另外一个非常关键的降低时间复杂度的方法是在hash中保存那个key在链表中对应的指针, 我们知道链表要查找一个结点的时间复杂度是O(n), 所以当我们需要移动一个结点到链表首部的时候, 如果直接在链表中查询那个key所对于的结点, 然后再移动, 这样时间复杂度将会是O(n), 而一个很好的改进方法是在hash表中存储那个key在链表中结点的指针, 这样就可以在O(1)的时间内移动结点到链表首部.

STL技巧:

1、使用map的find方法来判断key是否已经存在,返回值和map的end迭代器比较;

2、使用unordered_map,它是hash_map,存取时间都是O(1),用它存储元素的position迭代器,是为了方便splice函数调用list.splice(position, list, element_pos)函数作用是把list的element_pos处的元素插入到position位置,本题中为了移动元素到list头部

Python实现

这道题还挺麻烦的,我反正是短时间内做不出来,我看了一下解析,主要是利用了双向链表的方式,然后定义一个moveToHead,removeNode,removeTail的操作来辅助完成put和tail的O(1)时间复杂度。

class DlinkNode:
    def __init__(self, key=0, value=0):
        self.key = key
        self.value = value
        self.prev = None
        self.next = None

class LRUCache:

    def __init__(self, capacity: int):
        self.cache = dict()
        self.head = DlinkNode()
        self.tail = DlinkNode()
        self.head.next = self.tail
        self.tail.prev = self.head
        self.capacity = capacity
        self.size = 0


    def get(self, key: int) -> int:
        if key not in self.cache:
            return -1

        node = self.cache[key]
        self.moveToHead(node)
        return node.value


    def put(self, key: int, value: int) -> None:
        if key not in self.cache:
            node = DlinkNode(key, value)
            self.cache[key]=node
            self.addToHead(node)
            self.size +=1
            if self.size > self.capacity:
                removed = self.removeTail()
                self.cache.pop(removed.key)
                self.size -=1
        else:
            node = self.cache[key]
            node.value = value
            self.moveToHead(node)

    def addToHead(self, node):
        node.prev = self.head
        node.next = self.head.next
        self.head.next.prev = node
        self.head.next = node
    
    def removeNode(self, node):
        node.prev.next = node.next
        node.next.prev = node.prev
    
    def moveToHead(self, node):
        self.removeNode(node)
        self.addToHead(node)
    
    def removeTail(self):
        node = self.tail.prev
        self.removeNode(node)
        return node



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

reference

[leetcode] 146. LRU Cache 解题报告. https://blog.csdn.net/qq508618087/article/details/50995188

LRU的C++实现.https://blog.csdn.net/tinyway/article/details/24536327

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

农民小飞侠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值