【经典算法题】LRU缓存机制

【经典算法题】LRU缓存机制

Leetcode 0146 LRU缓存机制

题目描述:Leetcode 0146 LRU缓存机制

在这里插入图片描述

分析

  • 本题的考点:哈希表、双向链表

  • Java中可以直接使用LinkedHashMap就可以。

  • 初始化一个双向链表,双向链表中的节点中存储键、值、左指针、右指针;新建虚拟头结点L和虚拟尾结点R,让其相互指向。

  • 对于get函数:如果不存在直接返回-1;如果存在通过哈希表以及键找到这个节点p,并将其移到头结点(先让p从链表中删除,然后再将p插入到虚拟头结点后面)。

  • 对于put函数:如果存在,直接更新节点对应的值,然后将该节点移到头结点;如果不存在则判断缓存是否已满,如果已满删除尾结点,然后将新数据插入到头结点中。

  • 可以发现上述存在两个操作:删除某个节点p,向虚拟头结点后插入一个节点p,这两种操作的示意图如下:

在这里插入图片描述

代码

  • C++
class LRUCache {
public:

    struct Node {
        int key, val;
        Node *left, *right;
        Node (int _key, int _val): key(_key), val(_val), left(NULL), right(NULL) {}
    } *L, *R;  // L: 虚拟头结点; R: 虚拟尾结点
    unordered_map<int, Node*> hash;  // (键, 该键对应的节点)
    int n;

    LRUCache(int capacity) {
        n = capacity;
        L = new Node(-1, -1), R = new Node(-1, -1);
        L->right = R, R->left = L;
    }
    
    int get(int key) {
        if (!hash.count(key)) return -1;
        auto p = hash[key];
        remove(p);  // 从双向链表中删除p
        insert(p);  // 在虚拟头结点L后插入p
        return p->val;
    }
    
    void put(int key, int value) {
        if (hash.count(key)) {
            auto p = hash[key];
            p->val = value;
            remove(p);
            insert(p);
        } else {
            if (hash.size() == n) {
                auto p = R->left;
                remove(p);
                hash.erase(p->key);
                delete p;
            }
            auto p = new Node(key, value);
            insert(p);
            hash[key] = p;
        }
    }

    // 辅助函数
    void remove(Node *p) {  // 从双向链表中删除p
        p->left->right = p->right;
        p->right->left = p->left;
    }

    void insert(Node *p) {  // 在虚拟头结点L后插入p
        p->right = L->right;
        p->left = L;
        L->right->left = p;
        L->right = p;
    }
};
  • Java
class LRUCache extends LinkedHashMap<Integer, Integer> {
    private int capacity;

    public LRUCache(int capacity) {
        super(capacity, 0.75F, true);
        this.capacity = capacity;
    }

    public int get(int key) {
        return super.getOrDefault(key, -1);
    }

    public void put(int key, int value) {
        super.put(key, value);
    }

    @Override
    protected boolean removeEldestEntry(Map.Entry<Integer, Integer> eldest) {
        return size() > capacity;
    }
}
class LRUCache {

    static class Node {
        int key, val;
        Node left, right;
        public Node(int _key, int _val) {
            key = _key; val = _val; left = null; right = null;
        }
    }

    Node L = new Node(-1, -1), R = new Node(-1, -1);
    HashMap<Integer, Node> hash = new HashMap<>();
    int n;

    public LRUCache(int capacity) {
        n = capacity;
        L.right = R; R.left = L;
    }
    
    public int get(int key) {
        if (!hash.containsKey(key)) return -1;
        else {
            Node p = hash.get(key);
            remove(p);
            insert(p);
            return p.val;
        }
    }
    
    public void put(int key, int value) {
        if (hash.containsKey(key)) {
            Node p = hash.get(key);
            p.val = value;
            remove(p);
            insert(p);
        } else {
            if (hash.size() == n) {
                Node p = R.left;
                remove(p);
                hash.remove(p.key);
                p = null;  // help GC
            }
            Node p = new Node(key, value);
            hash.put(key, p);
            insert(p);
        }
    }

    // 辅助函数
    private void remove(Node p) {
        p.left.right = p.right;
        p.right.left = p.left;
    }

    private void insert(Node p) {
        p.right = L.right;
        p.left = L;
        L.right.left = p;
        L.right = p;
    }
}

时空复杂度分析

  • 时间复杂度: O ( 1 ) O(1) O(1)

  • 空间复杂度:和操作次数有关。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值