zoukankan      html  css  js  c++  java
  • Leetcode: LRU Cache

    题目

    Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations: get and set.

    get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.
    set(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.

    思路

    1. 双向链表支持常数时间增删元素, 单向链表配合 hash table 也可以实现, 但是实现相当复杂

    2. hash table 存储链表中的元素

    总结

    1. 双向链表要处理的情况比单向链表更复杂

    2. 单向链表处理时, 仅需考虑 head 的问题, 但双向链表则需要考虑

      a) 增元素时, 考虑链表是否为空即 head 问题

      b) 删元素时, 要考虑被删除的元素是否为 head 

      c) LRU 操作, 前移元素时, 需要考虑被前移的元素是否为 Head, 这一个 bug 浪费了 2 个小时

      d) 有一个优化, 即 LRU set miss 时, 不需要显式的删除再增加节点, 仅需将 tail 节点的 key, value 修改 然后 head 前进一步即可

    代码

    class Node {
    public:
    	int key, value;
    	Node *next, *pre;
    	Node(int _key, int _value):key(_key), value(_value), next(NULL), pre(NULL){}
    };
    class LRUCache{
    public:
    	int capacity;
    	int curSize;
    	unordered_map<int, Node*> mp;
    	Node *head;
        LRUCache(int capacity) {
    		this->capacity = capacity;
    		curSize = 0;
        }
        
        int get(int key) {
          if(mp.find(key) == mp.end())
    		  return -1;
    	  int val = mp.find(key)->second->value;
    	  set(key, val);
    	  return val;
        }
        
        void set(int key, int value) {
    		int ans = 0;
    		if(mp.find(key) == mp.end())
    			ans = -1;
    		if(ans == -1) { // 新建一个 item
    			if(curSize >= capacity) { // 已满, 需要删除一个 item
    				if(capacity == 1) {
    					mp.erase(mp.find(head->key));
    					head->key = key;
    					head->value = value;
    					mp[key] = head;
    					return;
    				}else{	
    					// 模拟删除队尾元素
    					Node *tail = head->pre;
    					mp.erase(mp.find(tail->key));
    					tail->key = key;
    					tail->value = value;
    					head = tail;
    					mp[key] = head;
    					return;
    				}
    			}
    			// 未满, 添加元素
    			if(curSize == 0) {
    				head = new Node(key, value);
    				head->pre = head;
    				head->next = head;
    				mp[key] = head;
    				curSize++;
    				return ;
    			}else {
    				Node *al = new Node(key, value);
    				al->pre = head->pre;
    				al->next = head;
    				al->pre->next = al;
    				head->pre = al;
    				head = al;
    				mp[key] = al;
    				curSize++;
    				return;
    			}
    		}else{
    			if(head->key == key) {
    			    head->value = value;
    			    mp[key] = head;
    			    return;
    			}
    			//cout << "here" << endl;
    			Node *mid = mp.find(key)->second;
    			mid->next->pre = mid->pre;
    			mid->pre->next = mid->next;
    			mid->value = value;
    			mid->next = head;
    			mid->pre = head->pre;
    			head->pre = mid;
    			mid->pre->next = mid;
    			head = mid;
    			mp[key] = mid;	// 修改 mp[key]
    			return;
    		}
    	}
    };
    

      

    Update 

    #include <iostream>
    #include <map>
    using namespace std;
    
    class ListNode1 {
    public:
        ListNode1(int _key, int _val) {
            key = _key;
            val = _val;
            pre = next = NULL;
        }
    
        ListNode1 *pre;
        int key;
        int val;
        ListNode1 *next;
    };
    
    class LRUCache{
    public:
        LRUCache(int capacity) {
            this->capacity = capacity;
            head = NULL;
            size = 0;
        }
        
        int get(int key) {
            if(mp.count(key) == 0)
                return -1;
            int value = mp[key]->val;
            set(key, value);
            return value;
        }
        
        void set(int key, int value) {
            if(capacity == 1) {
                mp.clear();
                head = new ListNode1(key, value);
                mp[key] = head;
    
                return;
            }
            if(mp.count(key) > 0) {
                ListNode1 *curNode = mp[key];
                curNode->val = value;
                
                if(curNode == head)
                    return;
    
                curNode->pre->next = curNode->next;
                curNode->next->pre = curNode->pre;
    
                head->pre->next = curNode;
                curNode->pre = head->pre;
                curNode->next = head;
                head->pre = curNode;
                head = curNode;
                
                return;
            }
    
            if(size < capacity) {
                
                size ++;
                ListNode1 *newNode = new ListNode1(key, value);
                mp[key] = newNode;
                if(size == 1) {
                    newNode->pre = newNode;
                    newNode->next = newNode;
                    head = newNode;
                    return;
                }
                head->pre->next = newNode;
                newNode->pre = head->pre;
                newNode->next = head;
                head->pre = newNode;
                head = newNode;
                return;
            }
            // size >= capacity
            ListNode1 *tail = head->pre;
            mp.erase(mp.find(tail->key));
            mp[key] = tail;
            tail->key = key;
            tail->val = value;
            head = tail;
    
        }
    private:
        int capacity;
        int size;
        map<int, ListNode1*> mp;
        ListNode1 *head;
    };
  • 相关阅读:
    SourceTree用法
    @Valid注解的使用
    mysql命令导入导出sql文件
    eclipse集成svn及使用
    eclipse设置
    @Component
    购物车单选全选,计算总价,出现个小问题,没找到.....
    十三、迭代器,分部类,文件流,内存流,缓存,枚举(IEnumerator接口),线程(单线程,多线程)
    十二、事件,委托,泛型委托,集合(泛型和非泛型),Lambda表达式(声明委托,使用委托,简单的委托示例,action<T>和func<t>委托,多播委托,匿名方法,Lambda表达式,参数,事件)
    十一、接口(接口的概念,实现,继承,实现)、抽象类与抽象方法(抽象类,抽象方法概念,使用)
  • 原文地址:https://www.cnblogs.com/xinsheng/p/3514968.html
Copyright © 2011-2022 走看看