LeetCode 146. LRU Cache

The most important thing  to solve this problem is to choose the right data structure.


#include <iostream>
#include <unordered_map>
using namespace std;

/*
  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 exisits 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 the new item.
*/
/*
1: get operation, once we get the value and result not equals to -1, we need to update
   the value to be the most recent used one.
2: set operation need to pay attentions to the capacity. Once it is full and set a new
   value need to delete the most recent visited ones.

   Inorder to complete these operations effciently, we need to consider the data structure.
   Represention of cache:
   1: Array, get takes O(N) time (key is not index), update takes O(N) time, set takes O(N).
   2: LinkList, get takes O(N) time, update takes O(1) time, set takes O(N) time.
   3: Stack, get takes O(N), update takes O(N), set takes O(N). (complicate to implement)
   4: Tree, get takes O(lgN), update takes O(lgN), set takes O(lgN). (complicate to implement)
   5: HashMap for get operation, take O(1), LinkList for Update and set. O(N) time.
   Seems the 5th choice beats others.
*/
class LRUCache {
private:
  struct ListNode {
    int key;
    int value;
    ListNode* next;
    ListNode(int x, int y) : key(x), value(y), next(NULL) {}
  };
  unordered_map<int, int> keyToValue;
  int cacheSize;
  ListNode* head;
private:
ListNode* UpdateToMostRecent(ListNode* head, int value) {
    ListNode* dummy = new ListNode(0, 0);
    dummy->next = head;
    ListNode* prev = dummy;
    ListNode* current = head;
    while(current) {
      if(current->key == value) {
        prev->next = current->next;
        current->next = dummy->next;
        dummy->next = current;
      } else {
        prev = current;
        current = current->next;
      }
    }
    ListNode* newHead = dummy->next;
    delete dummy;
    return newHead;
  }
  int getCapacity(ListNode* head) {
    int size = 0;
    ListNode* tmp = head;
    while(tmp) {
      size++;
      tmp = tmp->next;
    }
    return size;
  }
public:
    LRUCache(int capacity) {
      this->cacheSize = capacity;
      this->head = NULL;
    }

  int get(int key) {
    auto iter = keyToValue.find(key);
    if(iter != keyToValue.end()) {
      head = UpdateToMostRecent(head, iter->second);
      return iter->second;
    } else {
      return -1;
    }
  }

  void set(int key, int value) {
    auto iter = keyToValue.find(key);
    if(iter == keyToValue.end()) {
      keyToValue.insert({key, value});
      if(getCapacity(head) == cacheSize) {
        ListNode* tmp = head;
        while(tmp->next) {
          tmp = tmp->next;
        }
        tmp->next = new ListNode(key, value);
        ListNode* newHead = head->next;
        auto it = keyToValue.find(head->key);
        keyToValue.erase(it);
        delete head;
        head = newHead;
      } else {
        if(!head) head = new ListNode(key, value);
        else {
          ListNode* current = head;
          while(current->next) current = current->next;
          current->next = new ListNode(key, value);
        }
      }
    } else {
      ListNode* tmp = head;
      while(tmp) {
        if(tmp->key == key) {
          tmp->value = value;
        }
        tmp = tmp->next;
      }
    }
  }
};

int main(void) {
  LRUCache cache(3);
  cache.set(1, 11);
  cache.set(2, 12);
  cache.set(3, 13);
  cout << cache.get(1) << endl;
  cache.set(4, 14);
  cout << cache.get(1) << endl;
} 

A much much better version : using double linked list, maintain a head and a tail.

struct Node {
  int key;
  int value;
  Node* prev;
  Node* next;
};

class LRUCacheII{
  private int capacity;
  private map<int, Node> data;
  private Node head;
  private Node end;
  public LRUCacheII(int capacity) {
    this.capacity = capacity;
    this.data = new map<>();
  }

  // append node as the head
  void add(Node node) {
    node.next = NULL;
    node.prev = NULL;
    if(NULL == this.head) {
      this.head = node;
      this.end = node;
      return;
    }
    this.head.prev = node;
    node.next = this.head;
    this.head = node;
  }
  // remove a node from the double linked list.
  private void remove(Node node) {
    if(this.head == NULL || node == NULL) return;
    if(this.head == this.end && this.head == node) {
      this.head = NULL;
      this.end = NULL;
      return;
    }
    if(node = this.head)
      this.head.next.prev = NULL;
      this.head = this.head.next;
      return;
    if(node == this.end) {
      this.end.prev.next = NULL;
      this.end = this.end.prev;
      return;
    }
    node.prev.next = node.next;
    node.next.prev = node.prev;
  }

  private void moveFirst(Node node) {
    this.remove(node);
    this.add(node);
  }
  private void removeLast() {
    this.remove(this.end)
  }

  public int get(int key) {
    if(this.data.find(key)) {
      Node node = this.data.get(key);
      this.moveFirst(node);
      return node.data;
    }
    return -1;
  }
  void set(int key, int val) {
    if(this.data.find(key)) {
      Node node = this.data.get(key);
      this.moveFirst(node);
      node.data = val;
      return;
    }
    if(this.data.size() >= this.capacity) {
      int id = this.end.key();
      this.removeLast();
      this.data.erase(id);
    }

    Node node = new Node();
    node.key = key;
    node.data = val;
    this.add(node);
    this.data.insert(key, node);
  }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值