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.


这道题主要是实现“最近最少使用替换”算法。

Cache的大小是有限的,当增加新的值时,如果没有额外空间,就需要采用替换算法。替换算法的核心就是要维护一个状态,即:哪个值应该被替换出去,哪个值是最新的。

同时当调用get方法时,需要更新刚索引过的值,将其状态设置为最新,再更新其他值的状态,最近最少使用的那个值将更新为:下次被替换出去。set方法同样需要更新各个值的状态。


根据上述的分析,我们可以采用单向链表来实现该替换算法。该链表需要维护一个尾指针。我们将最新状态的值放置在尾部,最近最少使用的值放在头部。当没有额外空间时,加入新值,我们在尾部添加,同时删除头部的旧值。当更新值得状态时,对应的操作就是链表的删除和插入操作。


但是链表的缺点就是遍历耗时。如何在O(1)时间内访问到链表中的值呢?可以结合Hash表的性质。hash表内存储节点的key值和节点的指针。当调用get方法时,利用hashMap获取到包含该key的节点,时间为O(1)。此时,需要做的就是要维护hashmap和链表的一致性。


import java.util.HashMap;

public class LRUCache {
    private LinkList list;
    
    public LRUCache(int capacity) {
        list = new LinkList(capacity);
    }
    
    public int get(int key) {
        return list.get(key);
    }
    
    public void set(int key, int value) {
        list.set(key, value);
    }
    
    public void print(){
    	list.printList();
    }

class LinkList{
    private int capacity;//链表总长度
    private int size;//当前链表节点个数
    private Node head;//头指针
    private Node tail;//尾指针
    private HashMap<Integer, Node> map;
    
    public LinkList(int capacity){
        this.capacity = capacity;
        this.size = 0;
        head = new Node();
        tail = head;
        tail.next = null;
        map = new HashMap<Integer,Node>(capacity);
    }
    
    public int get(int key){
    	int val = -1;
        if(map.containsKey(key)){
        	Node node = map.get(key);
        	val = node.value;
        	this.update(node);//更新链表和hashmap状态
        	return val;
        }else{
        	return val;
        }
    }
    public void set(int key, int value){
    	if(map.containsKey(key)){
    		Node node = map.get(key);
    		node.value = value;
    		this.update(node);
    	}else{
    		Node node = new Node(key, value);
			node.next = null;
			tail.next = node;
			tail = node;
			map.put(key, node);
    		if(size < capacity){	
    			size++;   			
    		}else{
    			Node p = head.next;
    			int k = p.key;
    			head.next = p.next;
    			p.next = null;
    			p = null;
    			map.remove(k);
    		}
    	} 	
    	
    } 
    
//当调用get和set方法时,当前节点应该需要置于最新状态,即将该节点放置到链表的尾部。采用的是单向链表,节点的删除需要从头遍历链表到当前节点的前一个节点,时间
//时间复杂度为O(n),这里采用O(1)的时间复杂度删除节点p。
//交换节点p和p.next的值,此时删除p.next,即将该节点插入到尾部即可。但需要注意的是在hashmap中就要将p.key和p.next.key的节点交换一下,否则hashmap维护的节点
//就是错误的了。
 public void update(Node p){
    	if(p != tail){
    	    Node p2 = p.next;
    	    map.put(p.key, p2);//更新hashmap中的节点
    	    map.put(p2.key, p);//更新hashmap中的节点
            int temp = p.key;
            p.key = p2.key;
            p2.key = temp;
            temp = p.value;
            p.value = p2.value;
            p2.value = temp;       
            if(p2 != tail){
                p.next = p2.next;
                p2.next = null;
                tail.next = p2;
                tail = p2;             
            }
    	}
    }
    
    public void printList(){
    	Node p = head.next;
    	while(p != null){
    		System.out.print(p.key +"->" + p.value + ",");
    		p = p.next;
    	}
    	System.out.println();
    }
}

class Node{
    int key;
    int value;
    Node next;
    
    public Node(){
    }
    
    public Node(int key, int value){
        this.key = key;
        this.value = value;
    }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值