https://oj.leetcode.com/problems/lru-cache/
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.
public class LRUCache {
public LRUCache(int capacity) {
}
public int get(int key) {
}
public void set(int key, int value) {
}
}这题是属于有固定做法的题目,本质上就是一个哈希表和双向链表的结合使用。
双向链表的长度为capacity,节点内容为key和value两项。哈希表的使用是为了O(1)的时间锁定键所对应的节点位置,所以键放的是key,值放的是链表里的key对应存放value的节点。在链表长度没有达到capacity之前,每一次set都只需要不停增加链表和往hashmap里面放内容即可。当然,根据LRU的定义,如果get的东西存在于cache中的话,就将节点从中间取出,然后放到链表尾表示它是最新的。当添加的节点数目超过了capacity,每次新加一个键值对的时候就把头结点从链表以及其对应的HashMap的内容也删除了。就可以了。主要小心链表的边界情况即可,譬如get的是链表末尾和头指针即可。下面给出代码:
class LinkedListNode{
int val, key;
LinkedListNode next, prev;
LinkedListNode(int x, int key){
val = x;
this.key = key;
}
}
LinkedListNode head, tail;
int size, cap;
HashMap<Integer, LinkedListNode> cached_map;
public LRUCache(int capacity) {
cached_map = new HashMap<Integer, LinkedListNode>();
size = 0;
cap = capacity;
head = tail = null;
}
public int get(int key) {
if(cached_map.containsKey(key)){
LinkedListNode n = cached_map.get(key);
if(tail == n)
return n.val;
if(n == head)
head = head.next;
if(n.prev != null)
n.prev.next = n.next;
if(n.next != null)
n.next.prev = n.prev;
tail.next = n;
n.prev = tail;
tail = tail.next;
tail.next = null;
return n.val;
}else{
return -1;
}
}
public void set(int key, int value) {
if(cached_map.containsKey(key)){
LinkedListNode n = cached_map.get(key);
n.val = value;
if(n == tail)
return;
if(n == head)
head = head.next;
if(n.prev != null)
n.prev.next = n.next;
if(n.next != null)
n.next.prev = n.prev;
tail.next = n;
n.prev = tail;
tail = tail.next;
tail.next = null;
}else{
LinkedListNode n = new LinkedListNode(value,key);
cached_map.put(key, n);
if(head == null){
head = tail = n;
}else{
tail.next = n;
n.prev = tail;
tail = tail.next;
}
size++;
if(size > cap){
cached_map.remove(head.key);
head = head.next;
head.prev.next =null;
head.prev = null;
size--;
}
}
}根据之前一个公司给我的面试评价:代码重复太多,我稍微修改了一下代码结构。让代码重用率增加。
class ListNode{
ListNode next,prev;
Integer val, key;
ListNode(int val, int key){
this.key = key;
this.val = val;
}
}
class DList{
ListNode head, tail;
int capacity;
int size;
DList(int capacity){
this.capacity = capacity;
head = tail = null;
}
ListNode append(ListNode next){
if(head == null){
head = tail = next;
}else{
tail.next = next;
next.prev = tail;
tail = tail.next;
}
size++;
if(size > capacity){
return remove(head);
}
return null;
}
ListNode remove(ListNode node){
if(node == head)
head = head.next;
if(node == tail)
tail = tail.prev;
if(node.prev != null)
node.prev.next = node.next;
if(node.next != null)
node.next.prev = node.prev;
node.prev = null;
node.next = null;
size--;
return node;
}
void update(ListNode node){
remove(node);
append(node);
}
}
DList list = null;
HashMap<Integer, ListNode> cached = new HashMap<Integer, ListNode>();
public LRUCache(int capacity) {
list = new DList(capacity);
}
public int get(int key) {
if(cached.containsKey(key)){
ListNode curNode = cached.get(key);
list.update(curNode);
return curNode.val;
}else{
return -1;
}
}
public void set(int key, int value) {
if(cached.containsKey(key)){
ListNode curNode = cached.get(key);
curNode.val = value;
list.update(curNode);
}else{
ListNode next = new ListNode(value, key);
ListNode candidate = list.append(next);
cached.put(key, next);
if(candidate != null){
cached.remove(candidate.key);
}
}
}
本文介绍了一种实现LRU缓存的数据结构,通过结合哈希表与双向链表来支持快速获取与更新操作。文章详细解释了如何在容量限制下管理缓存,并提供了完整的代码实现。
797

被折叠的 条评论
为什么被折叠?



