题解LRU算法

LRU算法,最久未被使用算法,有一个固定大小的cache,当装不下任务的时候,就会选取,最久未被使用过的任务,进行淘汰。对于LRU要求有如下:
1,查找和删除都是O1级别的,O1级别立马就想到了hash表结构,满足这个要求。
2,要求把使用过的任务安放起来,用的时候,就去寻找,这个想到了用链表来实现。
实际上java中提供了这两种结构的结合题,这就是LinkedHashMap。用这种结构就能解决力扣上的LRU算法题,代码如下:

class LRUCache {

        private int cap;
	private Map<Integer, Integer> map = new LinkedHashMap<>();  // 保持插入顺序

	public LRUCache(int capacity) {
		this.cap = capacity;
	}

	public int get(int key) {
		if (map.keySet().contains(key)) {
			int value = map.get(key);
			map.remove(key);
                       // 保证每次查询后,都在末尾
			map.put(key, value);
			return value;
		}
		return -1;
	}

	public void put(int key, int value) {
		if (map.keySet().contains(key)) {
			map.remove(key);
		} else if (map.size() == cap) {
			Iterator<Map.Entry<Integer, Integer>> iterator = map.entrySet().iterator();
			iterator.next();
			iterator.remove();

			// int firstKey = map.e***ySet().iterator().next().getValue();
			// map.remove(firstKey);
		}
		map.put(key, value);
	}
}

但是一般来说,面试考察的就是你怎么去构建哪两种结构,一般是不会允许这样的,那么就需要手动的创建链表,和hash

  • 首先创建链表中的每个元素节点,节点中的属性有,key,value,pre(指向前一个节点),next(指向后一个节点)。
class Node{
      int key;
      int value;
      Node pre;
      Node next;
      public Node(int key,int value){
       this.key=key;
       this.value=value;
      }
      public Node(){
      }
}
  • 创建双向链表,双向链表里面的属性就少一些,是头节点,和尾节点
class DoubleList{//双链表head<->[key,val]<->tail
   //头节点
   Node head;
   //尾节点
   Node tail;
   public DoubleList(){//构造方法
       head=new Node(0,0);
       tail=new Node(0,0);
       head.next=tail;
       tail.pre=head;
   }
   public void addFirst(Node n){//头插法
     head.next.pre=n;
     n.next=head.next;
     head.next=n;
     n.pre=head;
   }
   //删除某个节点
   public void remove(Node n){
       n.pre.next=n.next;
       n.next.pre=n.pre;
       n.next=null;
       n.pre=null;
   }
   public Node removeLast(){
       //删除最后一个并且返回
       Node res=tail.pre;
       remove(res);
       return res;
   }
}
  • 接下来就是创建put 和get方法,思路是这样的,无论是put还是get后,都相当于操作了这个节点,所以一定要放在链表的头部。对于get方法,通过map可以快速的查到链表里是否含有这个节点,如果含有,就把他获取,删除,在次添加。对于set方法,如果已经有key相同的情况,就修改它的value。删除,放入队头。还要检测是否大于cache,如果大于,就把链表的最后一个删除。实现代码如下:
class LRUCache {
    HashMap<Integer,Node> map;
    DoubleList cache;
    int cap;//容量
    public LRUCache(int capacity) {
        map = new HashMap<>();
        cache = new DoubleList();
        this.cap = capacity;
    }
    
    public int get(int key) {
        if(!map.containsKey(key))//若该节点不存在
            return -1;
        Node res = map.get(key);
        cache.remove(res);
        cache.addFirst(res);
        return res.val;
    }
    
    public void put(int key, int value) {
        Node n = new Node(key,value);
        if(map.containsKey(key)){//若该节点已经存在
            cache.remove(map.get(key));
        }else if(map.size()==cap){//若该节点不存在,但是cache已满
            Node last = cache.removeLast();
            map.remove(last.key);
        }
        cache.addFirst(n);
        map.put(key,n);
    }
}

如有错误请指出

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值