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缓存机制的更多相关文章

  1. leetcode LRU缓存机制(list+unordered_map)详细解析

    运用你所掌握的数据结构,设计和实现一个  LRU (最近最少使用) 缓存机制.它应该支持以下操作: 获取数据 get 和 写入数据 put . 获取数据 get(key) - 如果密钥 (key) 存 ...

  2. [Leetcode]146.LRU缓存机制

    Leetcode难题,题目为: 运用你所掌握的数据结构,设计和实现一个  LRU (最近最少使用) 缓存机制.它应该支持以下操作: 获取数据 get 和 写入数据 put . 获取数据 get(key ...

  3. Java实现 LeetCode 146 LRU缓存机制

    146. LRU缓存机制 运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制.它应该支持以下操作: 获取数据 get 和 写入数据 put . 获取数据 get(key) - ...

  4. 【力扣】146. LRU缓存机制

    运用你所掌握的数据结构,设计和实现一个  LRU (最近最少使用) 缓存机制.它应该支持以下操作: 获取数据 get 和 写入数据 put . 获取数据 get(key) - 如果关键字 (key) ...

  5. 常见面试题之操作系统中的LRU缓存机制实现

    LRU缓存机制,全称Least Recently Used,字面意思就是最近最少使用,是一种缓存淘汰策略.换句话说,LRU机制就是认为最近使用的数据是有用的,很久没用过的数据是无用的,当内存满了就优先 ...

  6. Q200510-03-03 :LRU缓存机制

    LRU缓存机制运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制.它应该支持以下操作: 获取数据 get 和 写入数据 put . 获取数据 get(key) - 如果密钥 ( ...

  7. Q200510-03-02: LRU缓存机制

    问题: LRU缓存机制运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制.它应该支持以下操作: 获取数据 get 和 写入数据 put . 获取数据 get(key) - 如果 ...

  8. 力扣 - 146. LRU缓存机制

    目录 题目 思路 代码 复杂度分析 题目 146. LRU缓存机制 思路 利用双链表和HashMap来解题 看到链表题目,我们可以使用头尾结点可以更好进行链表操作和边界判断等 还需要使用size变量来 ...

  9. 146. LRU 缓存机制 + 哈希表 + 自定义双向链表

    146. LRU 缓存机制 LeetCode-146 题目描述 题解分析 java代码 package com.walegarrett.interview; /** * @Author WaleGar ...

  10. 【golang必备算法】 Letecode 146. LRU 缓存机制

    力扣链接:146. LRU 缓存机制 思路:哈希表 + 双向链表 为什么必须要用双向链表? 因为我们需要删除操作.删除一个节点不光要得到该节点本身的指针,也需要操作其前驱节点的指针,而双向链表才能支持 ...

随机推荐

  1. python - view() + UpsamplingBilinear2d()

    import torch from torch import nn # view函数的-1参数的作用在于基于另一参数,自动计算该维度的大小 # view的第一个参数:2 代表的是batch 后面的2, ...

  2. 【RocketMQ】RocketMQ 5.0新特性(三)- Controller模式

    在RocketMQ 5.0以前,有两种集群部署模式,分别为主从模式(Master-Slave模式)和Dledger模式. 主从模式 主从模式中分为Master和Slave两个角色,集群中可以有多个Ma ...

  3. Python:利用math和random模块实现RSA加密算法

    实验五报告: 利用math和random模块实现RSA加密算法 实验目标 本实验的主要目标是熟悉RSA(Rivest-Shamir-Adleman)密码算法的编写,其中包括求最大公因子.模逆的扩展欧几 ...

  4. 从零用VitePress搭建博客教程(6) -– 第三方组件库的使用和VitePress搭建组件库文档

    接上一节:从零用VitePress搭建博客教程(5) - 如何自定义页面模板.给页面添加独有的className和使页面标题变成侧边目录? 九.第三方组件库的使用 我们经常看见UI组件库的文档,这里我 ...

  5. #866 div1A

    A. Constructive Problem 题意:给定一个长度为n的非负数组a,我们可以进行一次操作,操作是将l~r这个区间内的所有数变为k(k >= 0),得到b,能不能使mex(a)+ ...

  6. 7/10 luoguRound 10 庆典 div3T1

    #include<bits/stdc++.h> using namespace std; int m,n,x; int arr[100005]; int maxi = -1,maxn = ...

  7. [透析] 卷积神经网络CNN究竟是怎样一步一步工作的?(转)

    视频地址:https://www.youtube.com/embed/FmpDIaiMIeA    转载:http://www.jianshu.com/p/fe428f0b32c1 文档参阅:pdf ...

  8. XOR加密

    coding=utf-8 md5算法 import hashlib h_md5 = hashlib.md5() x = input("输入需要加密的数据:") print( &qu ...

  9. Android学习day03【跑马灯】

    这个学习内容很简单,说一下自己笨蛋的点吧 要实现这种情况,我始终没有办法实现(也就是跑马灯,图片没办法显示) 后来发现 android:layout_width="wrap_content& ...

  10. linux防火墙使用及配置

    Linux防火墙使用及配置 介绍 防火墙是网络安全的重要组成部分,它帮助保护服务器和计算机免受未经授权访问.恶意攻击和各种网络威胁.在Linux系统中,有一些工具和技术可用于设置和配置防火墙,其中最常 ...