[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.

分析: 关键是对Least Recently Used (LRU) cache的理解,如果用链表,遇到一个结点,将链表中出现的这个结点全删除,然后在链表末尾加上这个结点。

链表末尾表示最近访问的结点,链表头表示最久前访问的结点,如果cache满了,要删除结点,就删除链表头结点。但这样做每次都要遍历链表,所以速度特别慢,

总是提示Time Limited Exceeded!

#include<iostream>
#include<map>

using namespace std;

struct Lnode
{
  int key0;
  int value0;
  Lnode *next;
  Lnode *pre;
  Lnode(int key,int value):key0(key),value0(value),next(NULL),pre(NULL){}
  Lnode():next(NULL),pre(NULL){}
};
class LRUCache{
public:
    int capacity;
    int    capacityNow;
    Lnode *head;
    Lnode *h ;
    map<int,int> ma,mNum;//ma记录key和value,mNum记录key和出现的次数
    
    
    LRUCache(int capacity)
    {
      this->capacity = capacity;
      this->capacityNow = 0;
      head = new Lnode;
      h = head;
    }
   
    void set(int key,int value)
    {
        int num;
        del(head,key);//
        if(ma.count(key)>0)//修改
        {
           mNum.clear();
           mNum[key]++;
           ma[key]=value;
           mNum[key]++;
           return;
        }
        
        if(this->capacityNow >= this->capacity)//添加
        {
            
           Lnode *pTobedeleted = head->next;
           while(mNum.count(pTobedeleted->key0)!=0 && this->capacityNow != 1)
           {
             
              pTobedeleted = pTobedeleted->next;
           }
           
           ma.erase(pTobedeleted->key0);
           Lnode *p0 = pTobedeleted->next;
           if(p0)
             p0->pre = head;
           head->next = p0;
           
           ma[key] = value;
           
           Lnode *pnew = new Lnode(key,value);
           h->next = pnew;
           pnew->pre = h;
           h = pnew;
           mNum.clear();
           mNum[key]++;
        }
        else
        {
            mNum.clear();
            mNum[key]++;
            ma[key] = value;
            this->capacityNow++;
            Lnode *p = new Lnode(key,value);
            h->next = p;
            p->pre = h;
            h = p;
            
        }
        

    }

    int get(int key)
    {
        

        if(ma.count(key)>0)
        {
            
            del(head,key);//
            mNum.clear();
            mNum[key]++;
            
            Lnode *pnew = new Lnode(key,ma[key]);
            h->next = pnew;
            pnew->pre = h;
            h = pnew;
           

            return ma[key];
        }
        else
           return -1;
    }
private:
    void del(Lnode *head,int key)
    {
       Lnode *p=head->next,*p1;
       Lnode *h1 = head;
       while(p)
       {
           
           p1 = p->next;
         if(p->key0 == key)
         {
           h1->next = p1;
           if(p1)
             p1->pre = h1;
         }
         h1 = p;
         p = h1->next;
       }
       if(h1->key0 == key)
           this->h = h1->pre;
       else
           this->h = h1;
    
      
    }
};

这道题如果稍微有一点需要遍历的,就会超时,以下是Accept的方法:

#include<iostream>
#include<map>

using namespace std;

struct Lnode
{
  int key0;
  int value0;
  Lnode *next;
  Lnode *pre;
  Lnode(int key,int value):key0(key),value0(value),next(NULL),pre(NULL){}
  Lnode():next(NULL),pre(NULL){}
};
class LRUCache{
public:
    int capacity;
    int    capacityNow;
    Lnode *head;
    Lnode *h ;
    map<int,int> ma,mNum;//ma记录key和value,mNum记录key和出现的次数
    
    
    LRUCache(int capacity)
    {
      this->capacity = capacity;
      this->capacityNow = 0;
      head = new Lnode;
      h = head;
    }
   
    void set(int key,int value)
    {
        
        if(ma.count(key)>0)//修改
        {
           
           ma[key]=value;

           Lnode *pnew = new Lnode(key,value);
           h->next = pnew;
           pnew->pre = h;
           h = pnew;
           
           mNum[key]++;
           return;
        }
        
        if(this->capacityNow >= this->capacity)//添加
        {
               
           Lnode *pTobedeleted = head->next;
           
           int num = mNum[pTobedeleted->key0];
           while(num !=1 || ma.count(pTobedeleted->key0)==0)//在链表中找到一个存在于ma的,且最久前没用的结点
           {
              mNum[pTobedeleted->key0]--;
              pTobedeleted = pTobedeleted->next;
              num = mNum[pTobedeleted->key0];
           }
           mNum[pTobedeleted->key0] = 0;
           head->next = pTobedeleted->next;
           ma.erase(pTobedeleted->key0);
           ma[key] = value;
           
           Lnode *pnew = new Lnode(key,value);
           h->next = pnew;
           pnew->pre = h;
           h = pnew;
           
           mNum[key]++;
        }
        else
        {
            
            mNum[key]++;
            ma[key] = value;
            this->capacityNow++;
            Lnode *p = new Lnode(key,value);
            h->next = p;
            p->pre = h;
            h = p;
            
        }
        

    }

    int get(int key)
    {
        

        if(ma.count(key)>0)
        {
            mNum[key]++;
            
            Lnode *pnew = new Lnode(key,ma[key]);
            h->next = pnew;
            pnew->pre = h;
            h = pnew;
           

            return ma[key];
        }
        else
           return -1;
    }
    
};

将访问到的结点不断的添加到链表中,同时cache满需要删除结点时,将链表的头结点往后移。用一个结点出现的次数mNum判断一个链表的结点是否是需要删除的结点。

原文地址:https://www.cnblogs.com/Xylophone/p/3843588.html