题目

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.

LRU Cache

    LRU是Least Recent Used的缩写,即最少使用的Cache置换算法。是为虚拟页式存储管理服务的。Cache是快速缓存。这是IT行业常常见到的概念。CPU中的Cache能极大提高存取指令和数据的时间,让整个存储器(Cache+内存)既有Cache的快速度,又有内存的大容量。
    Cache尽管速度快,可是容量有限。因此当Cache容量用完而又有新的内容加入进来的时候,就须要选取Cache中的部分内容进行舍弃,然后加入新的内容。LRU Cache的替换规则是:每次选取最久不被使用的内容进行舍弃,然后加入新的内容。之前上操作系统,老师告诉我的LRU Cache Algorithm中文翻译是近期最久未使用算法。

思路

    LRU的典型实现是double linked list + hash map。

原理是:

  1. 双向链表根据每一个节点近期被訪问的时间有序存储,近期被訪问的节点存储在表头,近期没有被訪问的节点存储的表尾,存储根据是由于:近期被訪问的节点在接下来的一段时间仍有非常大的概率被再次訪问到。

  2. 哈希表的作用是用来提高查找效率,假设不使用哈希表。则查找一个节点的时间复杂度是O(n)。而使用了哈希表,则每一个节点的查找时间复杂度为O(1)。
    查找(GET)操作:
  • 依据键值查找hashmap,假设没找到直接返回-1
  • 若找到相应节点node,则将其插入到双向链表表头
  • 返回node的value值
    插入(SET)操作:
  • 依据键值查找hashmap。假设找到。则直接将该节点移到表头就可以
  • 假设没有找到。首先推断当前Cache是否已满
  • 假设已满,则删除表尾节点
  • 将新节点插入到表头

AC代码

    AC代码例如以下,写的比較乱,事实上非常多方法是能够简洁复用的,可是这里之所以不改,是为了让大家更好的清楚LRU的流程和原理:
import java.util.HashMap;

public class LRUCache {
private HashMap<Integer, DoubleListNode> mHashMap;
private DoubleListNode head;
private DoubleListNode tail;
private int capacity;
private int currentsize; public LRUCache(int capacity) {
this.capacity = capacity;
this.currentsize = 0;
this.mHashMap = new HashMap<Integer, DoubleListNode>();
this.head = this.tail = null;
} public int get(int key) {
if (mHashMap.containsKey(key)) {
DoubleListNode tNode = mHashMap.get(key);
if (tNode == tail) {
if (currentsize > 1) {
removeNodeFromTail();
moveNodeToHead(tNode);
}
} else if (tNode == head) {
// do nothing
} else {
tNode.pre.next = tNode.next;
tNode.next.pre = tNode.pre;
moveNodeToHead(tNode);
}
return mHashMap.get(key).value;
} else {
return -1;
}
} private void removeNodeFromTail() {
tail = tail.pre;
if (tail != null) {
tail.next = null;
}
} private void moveNodeToHead(DoubleListNode node) {
head.pre = node;
node.next = head;
node.pre = null;
head = node;
} public void set(int key, int value) {
if (mHashMap.containsKey(key)) {
// 更新HashMap中相应的值,并将key相应的Node移至队头
DoubleListNode tNode = mHashMap.get(key);
tNode.value = value;
if (tNode == tail) {
if (currentsize > 1) {
removeNodeFromTail();
moveNodeToHead(tNode);
}
} else if (tNode == head) {
// do nothing
} else {
tNode.pre.next = tNode.next;
tNode.next.pre = tNode.pre;
moveNodeToHead(tNode);
} mHashMap.put(key, tNode);
} else {
DoubleListNode node = new DoubleListNode(key, value);
mHashMap.put(key, node);
if (currentsize == 0) {
head = tail = node;
currentsize += 1;
} else if (currentsize < capacity) {
moveNodeToHead(node);
currentsize += 1;
} else {
// 删除tail节点。而且添加一个head节点
mHashMap.remove(tail.key);
removeNodeFromTail(); // 添加头节点
moveNodeToHead(node);
}
}
} public static void main(String[] args) {
LRUCache lruCache = new LRUCache(1);
lruCache.set(2, 1);
System.out.println(lruCache.get(2));
lruCache.set(3, 2);
System.out.println(lruCache.get(2));
System.out.println(lruCache.get(3));
} private static class DoubleListNode {
public DoubleListNode pre;
public DoubleListNode next;
public int key;
public int value; public DoubleListNode(int key, int value) {
this.key = key;
this.value = value;
this.pre = this.next = null;
}
} }

LRU算法&amp;&amp;LeetCode解题报告的更多相关文章

  1. leetcode解题报告(2):Remove Duplicates from Sorted ArrayII

    描述 Follow up for "Remove Duplicates": What if duplicates are allowed at most twice? For ex ...

  2. 2021字节跳动校招秋招算法面试真题解题报告--leetcode206 反转链表,内含7种语言答案

    206.反转链表 1.题目描述 反转一个单链表. 示例: 输入: 1->2->3->4->5->NULL输出: 5->4->3->2->1-> ...

  3. LeetCode解题报告:Linked List Cycle && Linked List Cycle II

    LeetCode解题报告:Linked List Cycle && Linked List Cycle II 1题目 Linked List Cycle Given a linked ...

  4. 2021字节跳动校招秋招算法面试真题解题报告--leetcode19 删除链表的倒数第 n 个结点,内含7种语言答案

    2021字节跳动校招秋招算法面试真题解题报告--leetcode19 删除链表的倒数第 n 个结点,内含7种语言答案 1.题目描述 给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点. ...

  5. LeetCode 解题报告索引

    最近在准备找工作的算法题,刷刷LeetCode,以下是我的解题报告索引,每一题几乎都有详细的说明,供各位码农参考.根据我自己做的进度持续更新中......                        ...

  6. LeetCode解题报告:LRU Cache

    LRU Cache Design and implement a data structure for Least Recently Used (LRU) cache. It should suppo ...

  7. LeetCode解题报告—— Search in Rotated Sorted Array & Search for a Range & Valid Sudoku

    1. Search in Rotated Sorted Array Suppose an array sorted in ascending order is rotated(轮流,循环) at so ...

  8. LeetCode解题报告—— 1-bit and 2-bit Characters & 132 Pattern & 3Sum

    1. 1-bit and 2-bit Characters We have two special characters. The first character can be represented ...

  9. leetCode解题报告5道题(六)

    题目一: Longest Substring Without Repeating Characters Given a string, find the length of the longest s ...

随机推荐

  1. iOS开发 - NSBundle, NSDevice, NSLocale

    iOS的APP的应用开发的过程中,有时为了bug跟踪或者获取用反馈的需要自动收集用户设备.系统信息.应用信息等等,这些信息方便开发者诊断问题,当然这些信息是用户的非隐私信息,是通过开发api可以获取到 ...

  2. TDBGrideh表头自动排序设置

    自动显示标题行的升降排序标志符(▽降序△升序)并做相应排序DBGridEh组件可以在标题行单元格中显示小三角形升.降排序标志符图片,在运行时可点击标题行,图片自动切换并做相应排序. 具体属性设置如下: ...

  3. Chrome浏览器插件VisualEvent,可以方便的查看页面绑定的事件

    http://files.cnblogs.com/files/jiqing9006/VisualEvent.zip

  4. ios扩展机制objc_setAssociatedObject,objc_getAssociatedObject

    这个可以解决变量传递问题, 就不用定义全局的了. 使用例子: 首先导入头文件:#import <objc/runtime.h> 设置静态常量:static char alertinfoke ...

  5. Android Weekly Notes Issue #238

    Android Weekly Issue #238 January 1st, 2017 Android Weekly Issue #238 本期内容包括: Firebase发送Notification ...

  6. HDOJ/HDU 2565 放大的X(分段思考~)

    Problem Description 请你编程画一个放大的'X'. 如3*3的'X'应如下所示: X X XX X5*5的'X'如下所示:X X X X X X XX X Input 输入数据第一行 ...

  7. Ubuntu---2

    1.Ubuntu学习笔记之:安装中文语言包 http://askubuntu.com/questions/59356/how-do-i-get-chinese-input-to-work

  8. jQuery技术内幕预览版.pdf2

    第二章 构造jQuery对象 jQuery对象是一个类数组对象,含有连续的整型属性.length属性和大量的jQuery方法,$()是jQuery()的缩写 构造函数jQuery() 如果调用构造函数 ...

  9. JAVA--线程wait()、lnotify()和notifyAll()方法

    join()方法是Thread类的一个方法,而wait().notify().notifyAll()是java.lang.Object类的方法,这意味着,任何一个Java对象(包括线程对象)都有wai ...

  10. Java集合类操作优化经验总结

    本文首先针对 Java 集合接口进行了一些介绍,并对这些接口的实现类进行详细描述,包括 LinkedList.ArrayList.Vector.Stack.Hashtable.HashMap.Weak ...