题目
运用你所掌握的数据结构,设计和实现一个 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
算法实现
public class LRUCache
{
private List<int> Keys;
private Dictionary<int, int> a;
public LRUCache(int capacity)
{
Keys = new List<int>(capacity);
a = new Dictionary<int, int>(capacity);
}
public int Get(int key)
{
int resValue;
if (a.TryGetValue(key, out resValue))
{
Keys.RemoveAt(Keys.IndexOf(key));
Keys.Add(key);
return resValue;
}
else
return -1;
}
public void Put(int key, int value)
{
int Value = 0;
a.TryGetValue(key,out Value);
if (Value != 0)
{
a[key] = value;
Keys.RemoveAt(Keys.IndexOf(key));
Keys.Add(key);
}
else if (Keys.Count != Keys.Capacity)
{
Keys.Add(key);
a.Add(key, value);
}
else
{
a.Remove(Keys[0]);
Keys.RemoveAt(0);
Keys.Add(key);
a.Add(key, value);
}
}
}
执行结果
执行结果 : 通过
执行用时 : 480 ms, 在所有 C# 提交中击败了36.74%的用户
内存消耗 : 47.8 MB, 在所有 C# 提交中击败了26.67%的用户
小的总结
本题的要求让我想到了之前做过的辅助栈与数据栈,我想的是一个列表储存键的排序,另一个字典储存键值对。之后看了官方的双向链表加哈希的方法,是满足进阶的要求。发现题解没有C#的,于是移植到C#上稍加改进,然后顺手发了一个C#的题解,如下。
官方题解
public class LRUCache
{
class DLinkedNode
{
public int key;
public int value;
public DLinkedNode prev;
public DLinkedNode next;
}
private void addNode(DLinkedNode node)
{
//将新的node加入在头部的后面
node.prev = head;
node.next = head.next;
head.next.prev = node;
head.next = node;
}
private void removeNode(DLinkedNode node)
{
//从链表中移除一个node
DLinkedNode prev = node.prev;
DLinkedNode next = node.next;
prev.next = next;
next.prev = prev;
}
private void moveToHead(DLinkedNode node)
{
//将一个node移到队头
removeNode(node);
addNode(node);
}
private DLinkedNode popTail()
{
//移除当前队尾的元素
DLinkedNode res = tail.prev;
removeNode(res);
return res;
}
private Hashtable cache = new Hashtable();
private int size;
private int capacity;
private DLinkedNode head, tail;
public LRUCache(int capacity)
{
this.size = 0;
this.capacity = capacity;
head = new DLinkedNode();
// head.prev = null;
tail = new DLinkedNode();
// tail.next = null;
head.next = tail;
tail.prev = head;
}
public int Get(int key)
{
DLinkedNode node = (DLinkedNode)cache[key];
if (node == null) return -1;
// 将已存在的node移到队头
moveToHead(node);
return node.value;
}
public void Put(int key, int value)
{
DLinkedNode node = (DLinkedNode)cache[key];
if (node == null)
{
DLinkedNode newNode = new DLinkedNode();
newNode.key = key;
newNode.value = value;
cache.Add(key, newNode);
addNode(newNode);
++size;
if (size > capacity)
{
//移除队尾元素
DLinkedNode tail = popTail();
cache.Remove(tail.key);
--size;
}
}
else
{
// 更新node的值并移到队头
node.value = value;
moveToHead(node);
}
}
}