题解 | #设计LRU缓存结构#
设计LRU缓存结构
http://www.nowcoder.com/practice/e3769a5f49894d49b871c09cadd13a61
这道题总体来说比较复杂。首先说一下本题主要用的思想是hashmap+双向链表。
为什么要使用hashmap,因为这样在根据key取值的时候很快,如果只有一个双向链表,那么需要遍历去找值,很麻烦。
为什么要使用双向链表,因为会不断涉及到元素的插入删除,如果单链表删除的话很麻烦。
首先就是定义一个数据结构:
static class Node{ int k,v; Node pre,next; public Node(int k,int v) { this.k = k; this.v = v; } }然后遍历输入的数组。
int num = 0;
int count = 0;
for(int i=0;i<operators.length;i++){
if(operators[i][0]==2){
num++;
}
}
int[] ret = new int[num];
HashMap<Integer,Node> map = new HashMap<>();
for(int i=0;i<operators.length;i++){
if(operators[i][0]==1){
put(map,operators[i][1],operators[i][2],k);
}else{
ret[count++]=get(map,operators[i][1]);
}
}
return ret;
那么关键就在于插入和获取操作。
插入操作需要注意一点的是覆盖问题,如果这个元素已经了有了,那么从map中取出来,将其value值改一下即可。并且要把这个节点移动到结尾。如果这个节点本身就在结尾那么不用移动。
正常的插入就是
如下代码:
public static void put(HashMap<Integer,Node> map,int k,int v,int size){
//覆盖没有考虑
Node p = new Node(k,v);
if(map.containsKey(k)){
Node node = map.get(k);
node.v = v;
map.put(k,node);
//把这个节点移动到尾部
if(node.next!=null){
pre.next = node;
node.pre = pre;
pre = node;
head = head.next;
head.pre=null;
node.next = null;
}
return;
}
map.put(k,p);
if(n==0){
head = p;
}
n++;
p.next = null;
p.pre = pre;
if(pre!=null){
pre.next = p;
}
pre = p;
if(map.size()>size){
map.remove(head.k);
head = head.next;
head.pre = null;
}
}
如果这个元素就在尾部,那么不需要移动。
如果这个元素不在尾部,那么需要改变链表结构。
如果这个元素不在尾部,那么需要改变链表结构。
如果map根本就没这个元素那么直接返回-1
如果这个元素在头部那么也需要做特殊处理
public static int get(HashMap<Integer,Node> map,int k){
if(!map.containsKey(k)){
return -1;
}
Node node = map.get(k);
if(node.pre==null){
pre.next = node;
node.pre = pre;
head = node.next;
head.pre = null;
node.next=null;
pre = node;
}else if(node.next==null){
//这个节点本身就在尾部,不需要移动
System.out.println("1");
}else{
node.pre.next = node.next;
node.next.pre = node.pre;
pre.next = node;
node.next = null;
node.pre = pre;
pre = node;
}
return node.v;
}
