LeetCode LRU缓存机制
146. LRU缓存机制
运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制。它应该支持以下操作: 获取数据 get 和 写入数据 put 。
获取数据 get(key) - 如果关键字 (key) 存在于缓存中,则获取关键字的值(总是正数),否则返回 -1。
写入数据 put(key, value) - 如果关键字已经存在,则变更其数据值;如果关键字不存在,则插入该组「关键字/值」。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。
进阶:
你是否可以在 O(1) 时间复杂度内完成这两种操作?
示例:
LRUCache cache = new LRUCache( 2 /* 缓存容量 */ );
cache.put(1, 1);
cache.put(2, 2);
cache.get(1); // 返回 1
cache.put(3, 3); // 该操作会使得关键字 2 作废
cache.get(2); // 返回 -1 (未找到)
cache.put(4, 4); // 该操作会使得关键字 1 作废
cache.get(1); // 返回 -1 (未找到)
cache.get(3); // 返回 3
cache.get(4); // 返回 4
solution1
//调用Java底层的LinkedHashMap实现LRU
class LRUCache {
private int cap;
private LinkedHashMap<Integer,Integer> cache = new LinkedHashMap<>();
public LRUCache(int capacity) {
this.cap = capacity;
}
public int get(int key) {
if (!cache.containsKey(key)){
return -1;
}
makeRecently(key);
return cache.get(key);
}
public void put(int key, int value) {
if (cache.containsKey(key)){
cache.put(key,value);
makeRecently(key);
return;
}
if (cache.size() >= cap){
//获取链表头(map->set->Interator->取第一个元素)
int headKey = cache.keySet().iterator().next();
cache.remove(headKey);
}
cache.put(key,value);
}
//移到链表尾
private void makeRecently(int key){
int value = cache.get(key);
cache.remove(key);
cache.put(key,value);
}
}
solution2
public class LRUCache {
//链表节点
class Node{
public int key, val;
public Node next, prev;
public Node(int k, int v){
this.key = k;
this.val = v;
}
}
private Map<Integer,Node> cache = new HashMap<>();
private int size;
private int cap;
private Node head,tail;
public LRUCache(int capacity) {
this.size = 0;
this.cap = capacity;
//使用头尾虚拟节点
head = new Node(0,0);
tail = new Node(0,0);
head.next = tail;
tail.prev = head;
}
// 获取元素,从cache中获得val,node移到链表头
public int get(int key){
Node node = cache.get(key);
if(node == null){
return -1;
}
moveToHead(node);
return node.val;
}
public void put(int key, int value){
Node node = cache.get(key);
if(node == null){
//新建节点插入
Node newNode = new Node(key,value);
cache.put(key,newNode);
addToHead(newNode);
size++;
if (size>cap){
Node overNode = removeTail();
cache.remove(overNode.key);
size--;
}
}else{
//重新赋值节点,移到表头
node.val = value;
moveToHead(node);
}
}
private void addToHead(Node node){
node.prev = head;
node.next = head.next;
head.next.prev = node;
head.next = node;
}
private void moveToHead(Node node){
removeNode(node);
addToHead(node);
}
private void removeNode(Node node){
node.prev.next = node.next;
node.next.prev = node.prev;
}
private Node removeTail(){
Node node = tail.prev;
removeNode(node);
return node;
}
}
//思路1:deque 记录cache顺序,map存取键值对
//思路2:哈希链表 使用LinkedHashMap构建
//思路3:手写双向链表 + HashMap 》put时检查,map是否存在,重新赋值或新增,链表新增。get时从map获取,链表移到最前面
LeetCode LRU缓存机制的更多相关文章
- leetcode LRU缓存机制(list+unordered_map)详细解析
运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制.它应该支持以下操作: 获取数据 get 和 写入数据 put . 获取数据 get(key) - 如果密钥 (key) 存 ...
- [Leetcode]146.LRU缓存机制
Leetcode难题,题目为: 运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制.它应该支持以下操作: 获取数据 get 和 写入数据 put . 获取数据 get(key ...
- Java实现 LeetCode 146 LRU缓存机制
146. LRU缓存机制 运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制.它应该支持以下操作: 获取数据 get 和 写入数据 put . 获取数据 get(key) - ...
- 【力扣】146. LRU缓存机制
运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制.它应该支持以下操作: 获取数据 get 和 写入数据 put . 获取数据 get(key) - 如果关键字 (key) ...
- 常见面试题之操作系统中的LRU缓存机制实现
LRU缓存机制,全称Least Recently Used,字面意思就是最近最少使用,是一种缓存淘汰策略.换句话说,LRU机制就是认为最近使用的数据是有用的,很久没用过的数据是无用的,当内存满了就优先 ...
- Q200510-03-03 :LRU缓存机制
LRU缓存机制运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制.它应该支持以下操作: 获取数据 get 和 写入数据 put . 获取数据 get(key) - 如果密钥 ( ...
- Q200510-03-02: LRU缓存机制
问题: LRU缓存机制运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制.它应该支持以下操作: 获取数据 get 和 写入数据 put . 获取数据 get(key) - 如果 ...
- 力扣 - 146. LRU缓存机制
目录 题目 思路 代码 复杂度分析 题目 146. LRU缓存机制 思路 利用双链表和HashMap来解题 看到链表题目,我们可以使用头尾结点可以更好进行链表操作和边界判断等 还需要使用size变量来 ...
- 146. LRU 缓存机制 + 哈希表 + 自定义双向链表
146. LRU 缓存机制 LeetCode-146 题目描述 题解分析 java代码 package com.walegarrett.interview; /** * @Author WaleGar ...
- 【golang必备算法】 Letecode 146. LRU 缓存机制
力扣链接:146. LRU 缓存机制 思路:哈希表 + 双向链表 为什么必须要用双向链表? 因为我们需要删除操作.删除一个节点不光要得到该节点本身的指针,也需要操作其前驱节点的指针,而双向链表才能支持 ...
随机推荐
- Jmeter-变量的嵌套使用
场景: 有存在获取到多个登录账号,循环获取单个变量的情况. 常用方法: ${__BeanShell(vars.get("变量字段_${变量字段}"))} 取值示例: 思维扩展: 一 ...
- DHCP和PXE是怎么工作的
dhcp(Dynamic Host Configuration Protocol):配置一段共享IP地址,为新上线的机器分配IP地址,回收下线机器的IP地址. 正常情况下主机(DHCP client) ...
- 【RocketMQ】RocketMQ 5.0新特性(二)- Pop消费模式
Pop模式消费和消息粒度负载均衡 在RocketMQ 5.0之前,消费有两种方式可以从Broker获取消息,分别为Pull模式和Push模式. Pull模式:消费需要不断的从阻塞队列中获取数据,如果没 ...
- 02-oracle11g rac RMAN备份恢复至单机(未验证)
在一节点上进行全备确定备份路径,并赋予属组mkdir /rmanbackupchown oracle:oinsatll /rmanbackup进入rman进行全备rman target /run{al ...
- tunm二进制协议在python上的实现
tunm二进制协议在python上的实现 tunm是一种对标JSON的二进制协议, 支持JSON的所有类型的动态组合 支持的数据类型 基本支持的类型 "u8", "i8& ...
- 用结构化思维解一切BUG(1):核心思路
面对万"卷"世界,有人选择拼命学习新技术,解决眼前的.点状问题:有人提升思维层级,解决未来的.系统问题.您选择什么? 背景 我有10多年编程经验和研发管理经历,虽很久不写代码,但有 ...
- Markdown使用心得(简单用法解析)
Markdown使用心得(简单用法解析) Markdown的优势 个人看来,MD的优势在于脱离对鼠标的依赖,在简单的熟悉后,从段落格式到字体特效的实现都可以完全脱离鼠标.避免了为了格式和艺术效果多次将 ...
- JavaScript高级程序设计笔记04 变量、作用域与内存
变量.作用域与内存 变量 特定时间点一个特定值的名称. 分类 原始值:按值访问 复制:两个独立使用.互不干扰 引用值(由多个值构成的对象):按引用访问 操作对象时,实际上操作的是对该对象的引用(ref ...
- 使用MVVM Toolkit简化WPF开发
最近. NET 8 的 WPF 推出了 WPF File Dialog改进,这样无需再引用 Win32 命名空间就可以实现文件夹的选择与存储了,算是一个很方便的改进了.顺手写了一个小的 WPF 程序, ...
- java笔记——面向对象
1.概述:面向对象是基于面向过程的编程思想 举例:把大象装进冰箱 2.开发:不断的创建对象,使用对象,指挥对象做事情 3.面向对象特征:封装 , 继承 , 多态 4.类和对象的关系: 类是一组相关的属 ...