欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【设计】B001_用队列实现栈(双端队列 + Map / Map + 自定义双向链表 (代办))

程序员文章站 2022-06-12 22:50:46
...

一、Problem

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.

The cache is initialized with a positive capacity.

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


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

二、Solution

方法一:暴力做法

直接用 Map + LinkedList 做:

  • put 时,检查 key 是否有对应的 v
    • 如果有,则覆盖掉 Map 中的值,并且 q 的大小不能查过 cap,如果超了,pollFirst
    • 否则,map 添加键值对
  • get 时,也是先判空,此时的 key 为使用过,所以要变新。

删除操作耗费时间…

class LRUCache {
    Map<Integer, Integer> mp;
    ArrayDeque<Integer> q;
    int cap;
    public LRUCache(int capacity) {
        mp = new HashMap<>(capacity);
        q = new ArrayDeque<>();
        cap = capacity;
    }
    
    public int get(int key) {
        Integer v = mp.get(key);
        if (v != null) {
            q.remove(key);
            q.add(key);
            return v;
        }
        return -1;
    }
    
    public void put(int key, int value) {
        Integer v = mp.get(key);
        if (v != null) {
            q.remove(key);
            q.add(key);
        } else if (q.size() < cap){
            q.add(key);
        } else {
            int oldKey = q.pollFirst();
            q.add(key);
            mp.remove(oldKey);
        }
        mp.put(key, value);
    }
}

复杂度分析

  • 时间复杂度:O(...)O(...)
  • 空间复杂度:O(...)O(...)

方法二:双向链表 + Map

  • 定义一个 Node 内部类,存储 k、v、pre、next
  • map 就存储 <K, Node> 类型的键值对,这样就可以通过 k 用 O(1)O(1) 的时间找到 v,然后通过修改指针的指向来删除结点和添加结点。

复杂度分析

  • 时间复杂度:O(1)O(1)
  • 空间复杂度:O(cap)O(cap)
相关标签: # 【设计】