Leetcode's LRU Cache

Source: Internet
Author: User
Tags prev

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 ('ll always be positive) of the key if the key ex Ists 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.


The title is as above.

The first code, the idea is to use a reference counter to achieve, function through, but because to maintain this counter constantly and inefficient result in accepted.


public class LRUCache {class Cache {int key;int value;int count;} Cache[] Cc;public LRUCache (int capacity) {Cc = new Cache[capacity];for (int i = 0; i < cc.length; i++) {Cc[i] = new Cac He (); Cc[i].value =-1; Cc[i].count = i;}} public int get (int key) {for (int i = 0; i < cc.length; i++) {if (Cc[i].key = = key) {if (Cc[i].count! = cc.length-1) {cc[i].count = cc.length-1;for (int j = 0; J < Cc.length; J + +) {cc[j].count--;}} return cc[i].value;}} return-1;} public void set (int key, int value) {for (int i = 0; i < cc.length; i++) {cc[i].count--;if (Cc[i].count = =-1) {CC[I].K EY = key; Cc[i].value = value; Cc[i].count = Cc.length-1;}}} public static void Main (string[] args) {LRUCache LRU = new LRUCache (ten); Lru.set (2, 2); Lru.set (3, 2); Lru.set (one, 9); t i = 0; I < LRU. Cc.length; i++) {System.out.println (LRU. Cc[i].key + "Count" + LRU. cc[i].count+ "value" + LRU. Cc[i].value);} System.out.println (Lru.get (11));}}

Then I quietly optimized a bit. The idea is still the same. But a lot less redundant variables.

Class Map {int key;int value;} Map[] Map;int capacity;public LRUCache (int capacity) {map = new Map[capacity];for (int i = 0; i < capacity; i++) {Map[i ] = new Map ();} This.capacity = capacity;} public int get (int key) {int i = capacity-1;int result =-1; Map temp = new map (), while (i > 0) {if (Map[i].key = = key) {result = Map[i].value;temp = Map[i];while (I < capacity -1) {Map[i] = map[i + 1];i++;} Map[capacity-1] = temp;break;} i--;} return result;} public void set (int key, int value) {int i = 0;while (i < capacity-1) {Map[i].key = map[i + 1].key;map[i].value = map [i + 1].value;i++;} Map[capacity-1].key = Key;map[capacity-1].value = value;}

But still did not pass:

Time Limit exceeded then don't be indifferent. The main problem is how to maintain a pipeline. And it can be ordered in order. The problem is how to ' press ' the number when it is unavoidable to use the loop to back-press the data.

And then.. Thought of. Pointer.. Then there is the natural list, with keys and value that can actually be used with HashMap. But you don't want to use what you already have. So I decided to write a simple-to-complex code.

The first one: Linkedhashmap with Java inside. It's all out of the way.
It's like cheating.
public class LRUCache {    private int capacity;    Private Map<integer, integer> Map;    public LRUCache (int c) {      this.capacity = C;      This.map = new Linkedhashmap<integer, integer> (capacity, 0.75f, true) {        protected Boolean removeeldestentry ( Map.entry<integer, integer> eldest) {            return size () > capacity;}}      ;    }    public int get (int key) {        if (!map.containskey (key)) {            return-1;        }        return Map.get (key);    }    public void set (int key, int value) {        map.put (key, value);}    }


The second one is to write a list of your own. And then use the HashMap
Class Node {int key;int value; Node Next; Node Pre; Node (int key, int value) {This.key = Key;this.value = value;}} int capacity; Hashmap<integer, node> map; Node head = new Node (-1,-1); Node tail;int size = 0;public LRUCache (int capacity) {this.capacity = Capacity;map = new Hashmap<integer, Lrucache.node > (capacity);} public int get (int key) {Node temp = map.get (key), if (temp = = null) {return-1;} else {RemoveNode (temp); temp = new Node (ke Y, Temp.value); Addnodetotail (temp); Map.put (key, temp); return temp.value;}} public void set (int key, int value) {Node temp = map.get (key); if (temp = = null) {if (size = = capacity) {RemoveHead ();} size++;} else {RemoveNode (temp);} temp = new Node (key, value); Addnodetotail (temp); Map.put (key, temp);} private void RemoveHead () {//TODO auto-generated method Stubmap.remove (Head.key), if (Size > 1) {head = Head.next;head. pre = NULL;} else {head = null;} size--;} private void RemoveNode (Node temp) {//TODO auto-generated method stubif (Size > 1) {if (temp.prE! = null) {//proves to be head node Temp.pre.next = Temp.next;} else {head = Head.next;head.pre = null;} if (temp.next! = null)//proves tail node {temp.next.pre = Temp.pre;} else {tail = Tail.pre;tail.next = null;}} else {tail = null;}} private void Addnodetotail (node node) {//TODO auto-generated method stubif (tail = = NULL | | head = = NULL) {head = Node;ta Il = Node;head.next = Tail;tail.pre = Head;head.pre = Null;tail.next = null;} else {tail.next = Node;node.pre = Tail;node.next = Null;tail = node;}}




You can see that you're writing a linked list that's a little more efficient. Mainly because of their single function. So it's the equivalent of streamlining unnecessary code and improving efficiency.

The third one is more challenging. That is, even hashmap to realize it.
The structure of the hashmap is particularly like a bead curtain. The same subscript data will be placed on a string of beads.


public class LRUCache {class Node {int key;int value; Node Next; Node Pre; Node (int key, int value) {This.key = Key;this.value = value;}} Class Map {int key; Node value; Map Next; MAP (int key, Node value) {This.key = Key;this.value = value;} Map (int key, Node value, map next) {This.key = Key;this.value = Value;this.next = Next;}} Map[] Mymap;int capacity = 0; Node head = new Node (-1,-1); Node tail;int size = 0;int mapsize = 1;public LRUCache (int capacity) {this.capacity = Capacity;while (Mapsize < capacit Y) {mapsize = Mapsize << 1;} Mymap = new Map[mapsize];}  public int get (int key) {int index = key & Mapsize-1;for (Map e = Mymap[index]; E! = null; e = e.next) {if (E.key = = Key) {RemoveNode (e.value); Node temp = new node (key, E.value.value); Addnodetotail (temp); e.value = Temp;return e.value.value;}} return-1;} public void set (int key, int value) {Node temp = new Node (key, value); int index = key & Mapsize-1; Map e = mymap[index];for (; E! = null; e = e.next) {if (E.key = = key) {REMOvenode (e.value); e.value = Temp;addnodetotail (temp); return;}} Map next = Mymap[index];mymap[index] = new map (key, temp, next), if (size = = capacity) {RemoveHead ();} Size++;addnodetotail (temp);} private void RemoveHead () {//TODO auto-generated method Stubint index = Head.key & Mapsize-1; Map prev = Mymap[index]; Map E = Prev;while (E! = null) {Map next = e.next;if (E.value.key = = Head.key) {if (prev = e) Mymap[index] = Next;elseprev . Next = Next;} Prev = E;e = Next;} if (Size > 1) {head = Head.next;head.pre = null;} else {head = null;} size--;} private void RemoveNode (Node temp) {//TODO auto-generated method stubif (Size > 1) {if (temp.pre! = null) {//prove to be head knot Point temp.pre.next = Temp.next;} else {head = Head.next;head.pre = null;} if (temp.next! = null)//proves tail node {temp.next.pre = Temp.pre;} else {tail = Tail.pre;tail.next = null;}} else {tail = null;}} private void Addnodetotail (node node) {//TODO auto-generated method stubif (tail = = null) {head = Node;tail = NODE;HEAD.N ext = Tail;tail. Pre = Head;head.pre = Null;tail.next = null;} else {tail.next = Node;node.pre = Tail;node.next = Null;tail = node;}} public static void Main (string[] args) {LRUCache LRU = new LRUCache (2); Lru.set (1, 1); Lru.set (2, 1); Get (LRU, 4); Lru.set (4, 1); Get (LRU, 1); Get (LRU, 2);////for (int i = 0; i < 4; i++) {//Get (LRU, i);////}///Get (LRU, 5);//Get (LRU, 9);  /Lru.set (8, 4);//Get (LRU, 7);//Lru.set (8, 5);//Get (LRU, 3);//Lru.set (+ 5);//Lru.set (5);//Lru.set (11, 5);// Lru.set (1123, 5);//Lru.set (5);//Get (LRU, 8);//Get (LRU);//Get (LRU, 113);//Get (LRU, 11); System.out.println ("---------------------------------------------"); while (lru.head! = null) {SYSTEM.OUT.PRINTLN ( Lru.head.key + "value" + lru.head.value); lru.head = Lru.head.next;} System.out.println ("---------------------------------------------" + lru.size); while (lru.tail! = null) { System.out.println (Lru.tail.key + "value" + lru.tail.value); lru.tail = Lru.tail.pre;} [Set (2,1), get (2), set (3,2), get (2), get (3)]//OuTput: [1,1,-1]//expected: [1,-1,1]//set (2,1), set (+), get (2), set (4,1), get (1), get (2)//SYSTEM.OUT.PRINTLN (8 & 15 );} private static void Get (LRUCache lru, int key) {System.out.println (Lru.get (key) + "key=" + Key);}}

Highly reference HashMap source code, and then partial reproduction, for Java 8 hashmap time will continue to implement, Java 8 in the implementation of HashMap, if the hash collision is very much will automatically convert to TreeMap

Main implementation difficulties and techniques:
int capacity = 0; Node head = new Node (-1,-1); Node tail;int size = 0;int mapsize = 1;public LRUCache (int capacity) {this.capacity = Capacity;while (Mapsize < capacit Y) {mapsize = Mapsize << 1;} Mymap = new Map[mapsize];}
At the time of initialization, find the smallest 2 of the n-th square that is larger than the set capacity.
Purpose: Used for subsequent calculation of the subscript, if you want to find the 5th number, 5&mapsize-1. For example mapsize at this time is 16, then is 5&15=5,101&1111=101=5. The magic is that when the scale is larger than size, for example, 16&15 will be equal to 0, that is, to achieve the purpose of cyclic assignment.



public void set (int key, int value) {Node temp = new Node (key, value); int index = key & Mapsize-1; Map e = mymap[index];for (; E! = null; e = e.next) {if (E.key = = key) {RemoveNode (e.value); e.value = Temp;addnodetotail (te MP); return;}} Map next = Mymap[index];mymap[index] = new map (key, temp, next), if (size = = capacity) {RemoveHead ();} Size++;addnodetotail (temp);}
The Set method is also debugging for a long time, suffering from Java does not support pointers so to add a constructor in the map, map (int key, node value, map next), will join the new node to the list header.

private void RemoveHead () {//TODO auto-generated method Stubint index = Head.key & Mapsize-1; Map prev = Mymap[index]; Map E = Prev;while (E! = null) {Map next = e.next;if (E.value.key = = Head.key) {if (prev = e) Mymap[index] = Next;elseprev . Next = Next;} Prev = E;e = Next;} if (Size > 1) {head = Head.next;head.pre = null;} else {head = null;} size--;}
Remove the head pointer, the key code is
                Map prev = Mymap[index]; Map E = Prev;while (E! = null) {Map next = e.next;if (E.value.key = = Head.key) {if (prev = e) Mymap[index] = Next;elseprev . Next = Next;} Prev = E;e = Next;}

Two variables prev and next are used to store the first and last node of the node to be deleted, and when the node E to be deleted is found, only the prev=next is needed.
if (prev = = e) is used to determine the first cycle is the Mymap[index] itself is not to delete the node, is the words directly equal to the next good.

The efficiency of this operation should naturally be higher than the previous one.





In order to re-optimize the constructor into
while (Mapsize < capacity*2) {mapsize = Mapsize << 1;}

To reduce the hash collision.




























Leetcode's LRU Cache

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.