• [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.

    Solution:

    数据结构

    LRU的典型实现是hash map + doubly linked list, 双向链表用于存储数据结点,并且它是按照结点最近被使用的时间来存储的。 如果一个结点被访问了, 我们有理由相信它在接下来的一段时间被访问的概率要大于其它结点。于是, 我们把它放到双向链表的头部。当我们往双向链表里插入一个结点, 我们也有可能很快就会使用到它,同样把它插入到头部。 我们使用这种方式不断地调整着双向链表,链表尾部的结点自然也就是最近一段时间, 最久没有使用到的结点。那么,当我们的Cache满了, 需要替换掉的就是双向链表中最后的那个结点(不是尾结点,头尾结点不存储实际内容)。

    如下是双向链表示意图,注意头尾结点不存储实际内容:

    头 --> 结 --> 结 --> 结 --> 尾
    结     点     点     点     结
    点 <-- 1  <-- 2 <-- 3  <-- 点
    

    假如上图Cache已满了,我们要替换的就是结点3。

    哈希表的作用是什么呢?如果没有哈希表,我们要访问某个结点,就需要顺序地一个个找, 时间复杂度是O(n)。使用哈希表可以让我们在O(1)的时间找到想要访问的结点, 或者返回未找到。

    http://huntfor.iteye.com/blog/2075379 

     1 package POJ;
     2 
     3 import java.util.ArrayList;
     4 import java.util.HashMap;
     5 import java.util.List;
     6 
     7 public class LRUCache {
     8     private HashMap<Integer, Node> hm=new HashMap<Integer, Node>();
     9     int capacity=0;
    10     Node head=new Node();
    11     Node tail=new Node();
    12 
    13     public LRUCache(int capacity) {
    14         this.capacity=capacity;
    15         head.next=tail;
    16         tail.pre=head;
    17     }
    18     
    19     public int get(int key) {
    20         if(hm.containsKey(key)){
    21             Node e=hm.get(key);
    22             delete(e);
    23             insert(head,e);
    24             return e.value;
    25         }
    26         return -1;
    27     }
    28     
    29     public void set(int key, int value) {
    30         Node e = new Node(key,value);
    31         if(hm.containsKey(key)){
    32             Node exist=hm.get(key);
    33             delete(exist);
    34             hm.remove(key);
    35             insert(head,e);
    36             hm.put(key, e);
    37         }else{
    38             if(hm.size()<capacity){
    39                 hm.put(key, e);
    40                 insert(head,e);
    41             }else if(hm.size()==capacity){
    42                 hm.remove(tail.pre.key);
    43                 delete(tail.pre);
    44                 insert(head,e);
    45                 hm.put(key, e);
    46             }
    47         }
    48     }
    49 
    50     private void insert(Node head, Node e) {
    51         // TODO Auto-generated method stub
    52         e.pre=head;
    53         e.next=head.next;
    54         head.next=e;
    55         e.next.pre=e;
    56     }
    57 
    58     private void delete(Node exist) {
    59         // TODO Auto-generated method stub
    60         Node pre= exist.pre;
    61         Node next=exist.next;
    62         pre.next=next;
    63         next.pre=pre;
    64     }
    65 }
    66 class Node{
    67     public int key;
    68     public int value;
    69     public Node pre;
    70     public Node next;
    71     public Node(){
    72         this.key=Integer.MIN_VALUE;
    73         this.value=Integer.MIN_VALUE;
    74         pre=null;
    75         next=null;
    76     }
    77     public Node(int key,int value){
    78         this.key=key;
    79         this.value=value;
    80         pre=null;
    81         next=null;
    82     }
    83 }
  • 相关阅读:
    动手动脑3
    动手动脑2
    编写一个文件分割工具,能把一个大文件分割成多个小的文件。并且能再次把他们合并起来得到完整的文件
    编写一个文件加解密程序通过命令行完成加解密工作
    编写一个程序指定一个文件夹,能自动计算出其总容量
    Java中常见的异常处理汇总
    覆盖 动手动脑
    课堂代码验证
    如何在静态方法中访问类的实例成员 及查询“你已经创建了多少个对象”
    Java的字段初始化规律
  • 原文地址:https://www.cnblogs.com/Phoebe815/p/4018952.html
Copyright © 2020-2023  润新知