leetcode:【集合】LRU Cache

| 分类 算法  | 标签 leetcode  collection 

问题描述

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.

code

/*
http://www.cs.uml.edu/~jlu1/doc/codes/lruCache.html
https://gist.github.com/Jeffwan/9926551
http://www.cnblogs.com/springfor/p/3869393.html
http://www.nowamagic.net/librarys/veda/detail/261

【What is LRU】
Least Recently Used (LRU) is a family of caching algorithms, which discards the least recently used items first.
This algorithm requires keeping track of when the item was used.

【Data Structure】
The key data structure of the algorithm is the combination of Hash Map and Doubly-Linked List. 
We initialize a Hash Map in a pre-defined size to store pairs, and use Doubly-Linked List to index the pairs in the order of data age.

【Why HashMap and Double Linked List】
HashMap could check if a value is in the list using O(1)
Double Linked List could delete a node and insert a node to rails using O(1).
List head, tails for delete or refresh,remark least recently used node
HashMap's key == LinkedList's key 

我的思路就是:
查找和设置,都在O(1)时间复杂度,无疑就是哈希表
而LRC需要标记map访问先后次序。也就是head-next-next-next-tail.
标记map数据访问次序,则需要标记key的次序。不需要时间戳,记录先后次序就行。
考虑一是数组,每次记录,刷新,则需要整体移动,直接pass
考虑二是链表,指针移动,方便。
考虑三是Linkedlist按照访问次序来记录刷新key信息。

访问map中一个即在key-value,因为key是最近访问,则将key提前到最先
【对于链表】map的key-value
对应在链表中的操作是pre-cur-next【pre-next,head = cur】
单向链表中,将实现删除时间复杂度为O(1)的删除链表结点方法,将next的信息赋值给cur就行
PS:假设要删除A节点,A.next==B。则删除B,并将B的值赋给A,这样就等于删除了A节点。
因为要标记head和tail,则map超过长度需要删除tail,tail-null,则无法获取tail的前者信息,只能是遍历全部,所以一般考虑双向链表。
自定义一个双向链表,存储key,当然为了简洁,可以将这个key和实际数据组成成一个value,直接存放在map中
【Linkedlist】很简单的思路
这个也和双向链表一样,比较容易实现

*/
public class LRUCache {
    private int capacity = 0;
    private Map<Integer, LRCNode> map = new HashMap<Integer, LRCNode>();
    private int len = 0;
    private LRCNode head = null;
    private LRCNode tail = null;
    
    public class LRCNode {
        int val;
        int key;
        LRCNode pre;
        LRCNode next;
        public LRCNode(int key, int val) {
            this.val = val;
            this.key = key;
            this.pre = null;
            this.next = null;
        }
    }
    
    public LRUCache(int capacity) {
        this.capacity = capacity;
    }
    
    public int get(int key) {
        if(map.containsKey(key)) {
            LRCNode lastest = map.get(key);
            remove(lastest);
            setHead(lastest);
            return lastest.val;
        } else {
            return -1;
        }
    }
    
    public void set(int key, int value) {
        if(map.containsKey(key)) {
            LRCNode temp = map.get(key);
            remove(temp);
            temp.val = value;
            setHead(temp);
        } else {
            LRCNode node = new LRCNode(key,value);
            if(len < capacity) { 
                map.put(key,node);
                setHead(node);
                len++;
            } else {
                map.remove(tail.key);
                remove(tail);
                map.put(key,node);
                setHead(node);
            }
        }
    }
    
    private void setHead(LRCNode node) {
        node.pre = null;
        node.next = head;
        if(head != null)
            head.pre = node;
        head = node;
        if(tail == null) 
            tail = node;
    }
    
    private void remove(LRCNode node) {
        LRCNode pre = node.pre;
        LRCNode cur = node;
        LRCNode next = node.next;
        if(pre != null) 
            pre.next = next;
        else {
            head = next;
        }
        if(next != null)
            next.pre = pre;
        else {
            tail = pre;
        }
    }
}


/*
LinkedList底层也是双链表实现的
可是Time Limit Exceeded
还是自己写点底层的,比价靠谱
*/

public class LRUCache {
	
    private Map<Integer,Integer> map = new HashMap<Integer,Integer>();
    private List<Integer> list = new LinkedList<Integer>();  
    private int len = 0;
    private int capacity;
    
    public LRUCache(int capacity) {
        this.capacity = capacity;
    }
    
    public int get(Integer key) {
        if(map.containsKey(key)) {
            list.remove(key);
            list.add(0,key);
            return map.get(key);
        } else {
            return -1;
        }
    }
    
    public void set(Integer key, int value) {
    	if(map.containsKey(key)) {
    		list.remove(key);
            list.add(0,key);
            map.put(key,value);
    	} else {
            if(len < capacity) {
	            list.add(0,key);
                map.put(key,value);
                len++;
            } else {
            	Integer oldKey = list.remove(len-1);
	            list.add(0,key);
                map.remove(oldKey);
                map.put(key,value);
            }
    		
    	}
    }
}


上一篇     下一篇