题目

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. MAC安装XAMPP的出现无法打开Apache server

    安装MAMP后,启动服务时提示Apache启动失败,80端口被占用.查看进程发现存在几个httpd. OS X自带Apache,可是默认是没有启动的.我也没有开启Web共享,怎么就开机启动了呢? 不知 ...

  2. keybd_event函数用法

    转自不用winio,直接达到驱动级模拟键盘效果的keybd_event函数用法 键盘模拟技术是在编写游戏外挂时经常使用的技术.但是由于很多游戏采用了directinput的方式,使得发送的一般键盘消息 ...

  3. 移动应用产品开发-android开发(二)

    这段时间实在太忙了,也没什么精力来写博客,还是没养成写博客的习惯,还是得记载下来,不然时间久了就忘记了. 早上一大早就来公司了,趁还早,拟定今天的工作内容和计划后,赶紧记载点东西. 最近做androi ...

  4. ANDROID_MARS学习笔记_S04_009_用java.lang.ref.SoftReference作缓存,android.os.Handler和new Thread异步加载略图片

    一.简介 二.代码流程 1.private Map<String, SoftReference<Drawable>> imageCache = new HashMap<S ...

  5. js常用操作代码

    页面前进后退<input type=button value=刷新 onclick="window.location.reload()"><input type= ...

  6. java学习之多生产者和多消费者

    在上一节当中我们说道了,java多线程当中单个消费者对应单个生产者的关系.这个时候有几个点需要注意一下,第一个就是把if判断flag的语句改成while这样能够避免,比如如果我们这个时候用if的话判断 ...

  7. hadoop2.2编程: 重写comparactor

    要点: 类型比较在hadoop的mapreduce中非常重要,主要用来比较keys; hadoop中的RawComparator<T>接口继承自java的comparator, 主要用来比 ...

  8. 【canvas】伸缩 / 剪裁 / 文本 / 阴影 / 填充图案 / 填充渐变

    <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8& ...

  9. Android webview中cookie增加/修改

    最近项目需求中,需要满足往webview传递cookie,而且cookie需要增加修改: public class MainActivity extends Activity { private We ...

  10. jQuery技术内幕预览版.pdf3

    jQuery.fn.init(selector,context,rootjQuery):构造函数 jQuery.fn.init() 负责解析参数 selector 和 context 的类型,并执行相 ...