LRU Cache
首先说明这是携程2019年后端的笔试题
https://www.nowcoder.com/question/next?pid=16620108&qid=365880&tid=35966796
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 64M,其他语言128M
``设计一个数据结构,实现LRU Cache的功能(Least Recently Used – 最近最少使用缓存)。它支持如下``2``个操作: get 和 put。` `int` `get(``int` `key) – 如果key已存在,则返回key对应的值value(始终大于``0``);如果key不存在,则返回-``1``。``void` `put(``int` `key, ``int` `value) – 如果key不存在,将value插入;如果key已存在,则使用value替换原先已经存在的值。如果容量达到了限制,LRU Cache需要在插入新元素之前,将最近最少使用的元素删除。` `请特别注意“使用”的定义:新插入或获取key视为被使用一次;而将已经存在的值替换更新,不算被使用。` `限制:请在O(``1``)的时间复杂度内完成上述``2``个操作。
输入描述:
第一行读入一个整数n,表示LRU Cache的容量限制。 从第二行开始一直到文件末尾,每1行代表1个操作。如果每行的第1个字符是p,则该字符后面会跟随2个整数,表示put操作的key和value。如果每行的第1个字符是g,则该字符后面会跟随1个整数,表示get操作的key。
输出描述:
按照输入中get操作出现的顺序,按行输出get操作的返回结果。
输入例子1:
2
p 1 1
p 2 2
g 1
p 2 102
p 3 3
g 1
g 2
g 3
输出例子1:
1
1
-1
3
例子说明1:
2 //Cache容量为2
p 1 1 //put(1, 1)
p 2 2 //put(2, 2)
g 1 //get(1), 返回1
p 2 102 //put(2, 102),更新已存在的key,不算被使用
p 3 3 //put(3, 3),容量超过限制,将最近最少使用的key=2清除
g 1 //get(1), 返回1
g 2 //get(2), 返回-1
g 3 //get(3), 返回3
第一版 —— 链表 ( get、put操作时间复杂度不为O(1))
import java.util.Scanner;
/**
* @author gyh
* @csdn https://blog.csdn.net/qq_40788718
* @date 2020/8/14 21:31
*/
public class LRUTest {
/** 双向链表 */
static class Node{
private int key ;
private int value ;
private Node pred ;
private Node next ;
public Node(int key, int value) {
this.key = key;
this.value = value;
}
}
static class LRU{
/** 头节点 */
private Node head ;
/** 尾节点 */
private Node tail ;
/** 链表的固定容量 */
private int capacity ;
/** 链表实际长度 */
private int size ;
public LRU(int capacity){
this.capacity = capacity ;
this.size = 0 ;
this.head = new Node(-1 , -1) ;
}
public int get(int key){
Node node = search(key) ;
//跳出来可能为空 或者找到key了
if (node != null){
delete(node);
insert(node);
return node.value ;
}
return -1 ;
}
public void put(int key , int value){
Node node = search(key) ;
if (node != null){
node.value = value ;
return ;
}
node = new Node(key , value) ;
//头插入
insert(node) ;
if (size > capacity){
//尾删除
delete(tail);
}
}
private Node search(int key) {
Node pre = head.next ;
while(pre != null && pre.key != key){
pre = pre.next ;
}
return pre ;
}
private void insert(Node node){
Node second = head.next ;
head.next = node ;
node.pred = head ;
node.next = second ;
if (second != null){
second.pred = node ;
}else {
tail = node ;
}
this.size ++ ;
}
private void delete(Node node){
if (node == null){
return ;
}
Node pred = node.pred ;
Node next = node.next ;
pred.next = next ;
if (next != null){
//node不是队尾
next.pred = pred ;
}else{
this.tail = pred ;
}
node.pred = null ;
node.next = null ;
this.size -- ;
}
public void print(){
System.out.println("====================");
Node pre = head.next ;
while(pre != null){
System.out.println(pre.key + " " +pre.value);
pre = pre.next ;
}
System.out.println("====================");
}
}
public static void main(String[] args) {
Scanner input = new Scanner(System.in) ;
LRU lru = new LRU(input.nextInt()) ;
while(input.hasNext()){
String choose = input.next() ;
if ("p".equals(choose)){
lru.put(input.nextInt() , input.nextInt());
}else if ("g".equals(choose)){
System.out.println(lru.get(input.nextInt())) ;
}
lru.print();
}
}
}
第二版 —— 链表+ 散列表(符合要求)
import java.util.HashMap;
import java.util.Scanner;
/**
* @author gyh
* @csdn https://blog.csdn.net/qq_40788718
* @date 2020/8/14 21:31
*/
public class LRUTest {
static class Node{
private int key ;
private int value ;
private Node pred ;
private Node next ;
public Node(int key, int value) {
this.key = key;
this.value = value;
}
}
static class LRU{
private Node head ;
private Node tail ;
// 加入 hashMap 用于 查找
private HashMap<Integer , Node> map ;
private int capacity ;
private int size ;
public LRU(int capacity){
this.map = new HashMap<>();
this.capacity = capacity ;
this.size = 0 ;
this.head = new Node(-1 , -1) ;
}
public int get(int key){
Node node = map.get(key) ;
//跳出来可能为空 或者找到key了
if (node != null){
delete(node);
insert(node);
return node.value ;
}
return -1 ;
}
public void put(int key , int value){
//Node node = search(key)
Node node = map.get(key) ;
if (node != null){
node.value = value ;
return ;
}
node = new Node(key , value) ;
insert(node) ;
if (size > capacity){
delete(tail);
}
}
private void insert(Node node){
Node second = head.next ;
head.next = node ;
node.pred = head ;
node.next = second ;
if (second != null){
second.pred = node ;
}else {
tail = node ;
}
map.put(node.key , node) ;
this.size ++ ;
}
private void delete(Node node){
if (node == null){
return ;
}
Node pred = node.pred ;
Node next = node.next ;
pred.next = next ;
if (next != null){
//node不是队尾
next.pred = pred ;
}else{
this.tail = pred ;
}
node.pred = null ;
node.next = null ;
map.remove(node.key) ;
this.size -- ;
}
public void print(){
System.out.println("====================");
Node pre = head.next ;
while(pre != null){
System.out.println(pre.key + " " +pre.value);
pre = pre.next ;
}
System.out.println("====================");
}
}
public static void main(String[] args) {
Scanner input = new Scanner(System.in) ;
LRU lru = new LRU(input.nextInt()) ;
while(input.hasNext()){
String choose = input.next() ;
if ("p".equals(choose)){
lru.put(input.nextInt() , input.nextInt());
}else if ("g".equals(choose)){
System.out.println(lru.get(input.nextInt())) ;
}
lru.print();
}
}
}
第三版 —— 有序散列表(LinkedHashMap)
package ctrip;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Scanner;
/**
* @author gyh
* @csdn https://blog.csdn.net/qq_40788718
* @date 2020/8/14 21:31
*/
public class Third {
// 省略 LRU
static class LRULinkedHashMap extends LRU {
private LinkedHashMap<Integer , Integer> cache ;
private int capacity = 0 ;
public LRULinkedHashMap(int capacity){
super(capacity);
cache=new LinkedHashMap<Integer,Integer>(capacity,0.75f,true){
@Override
protected boolean removeEldestEntry(java.util.Map.Entry<Integer, Integer> eldest) {
return size()>capacity;
}
};
}
@Override
public int get(int key){
return cache.getOrDefault(key , -1);
}
@Override
public void put(int key , int value){
cache.put(key , value) ;
}
}
public static void main(String[] args) {
Scanner input = new Scanner(System.in) ;
LRU lru = new LRULinkedHashMap(input.nextInt()) ;
while(input.hasNext()){
String choose = input.next() ;
if ("p".equals(choose)){
lru.put(input.nextInt() , input.nextInt());
}else if ("g".equals(choose)){
System.out.println(lru.get(input.nextInt())) ;
}
lru.print();
}
}
}