c# - LRU缓存问题的两种解决方案:为什么一种比另一种快?
问题描述
我提交了 leetcode 的 LRU 缓存问题的解决方案,它在运行时排名为 33%。然后我看到比其他提交速度快 98% 的提交几乎与我的相同,只是略有不同。我注意到的最大区别是,他们没有使用字典和整数链表,而是使用了用户定义的结构。我不明白为什么这会影响性能。谢谢!
我的解决方案:
public class LRUCache
{
Dictionary<int,int> LRUDict = new Dictionary<int,int>();
LinkedList<int> keys = new LinkedList<int>();
int capacity = 0;
public LRUCache(int capacity) {
this.capacity = capacity;
}
public int Get(int key) {
int retval = -1;
int entry;
if (LRUDict.TryGetValue(key,out entry))
{
retval = entry;
keys.Remove(key);
keys.AddLast(key);
}
return retval;
}
public void Put(int key, int value) {
//case 1: exists, no need to increment count and check capacity, just change value and move up
if (LRUDict.ContainsKey(key))
{
keys.Remove(key);
keys.AddLast(key);
}
//case 2: does not exist, need to add new entry, may need to kick out oldest one
else
{
keys.AddLast(key);
if (keys.Count > capacity)
{
int LRUKey = keys.First.Value;
keys.RemoveFirst();
LRUDict.Remove(LRUKey);
}
}
LRUDict[key] =value;
}
}
更快的解决方案:
public class LRUCache {
struct Cache {
public int Key { get;set; }
public int Val { get;set; }
}
private int _capacity;
private LinkedList<Cache> _cache = new LinkedList<Cache>();
private Dictionary<int, LinkedListNode<Cache>> _keys = new Dictionary<int, LinkedListNode<Cache>>();
public LRUCache(int capacity) {
_capacity = capacity;
}
public int Get(int key) {
if (_keys.TryGetValue(key, out var node)) {
_cache.Remove(node);
_cache.AddLast(node);
return node.Value.Val;
}
return -1;
}
public void Put(int key, int value) {
LinkedListNode<Cache> n;
var containsKey = _keys.TryGetValue(key, out n);
if (_cache.Count >= _capacity && !containsKey) {
var invalidNode = _cache.First;
_cache.RemoveFirst();
_keys.Remove(invalidNode.Value.Key);
}
if (containsKey) {
_cache.Remove(n);
}
var cache = new Cache { Key = key, Val = value };
var node = new LinkedListNode<Cache>(cache);
_cache.AddLast(node);
_keys[key] = node;
}
}
解决方案
第二种解决方案更快,因为它删除了 LinkedListNode,这可以在 O(1) 中完成。第一个解决方案删除一个值,这需要搜索链表或 O(n) 时间。
因此,第一个解决方案对于更多项目的扩展性会很差。
查看在这两种情况下使用的确切 Remove 方法重载 - 以及相应的文档。
LinkedList.Remove(T) - 在第一个解决方案中使用
删除指定值的第一次出现。此方法执行线性搜索;因此,此方法是 O(n) 操作..
LinkedList.Remove(LinkedListNode<T>) - 用于第二个解决方案
删除指定的节点。此方法是 O(1) 操作。
推荐阅读
- cypress - 赛普拉斯未通过测试视频录制无法处理
- csv - 在 Weka 中打开 CSV 文件时,如何解决此“错误数量的值”错误?
- java - java.lang.NullPointerException:无法调用“java.sql.Connection.prepareStatement(String)”返回值 null
- php - 将碳日期分块成连续的块
- php - 验证票证上的 4 个号码
- javascript - 在JS中返回多个值
- javascript - 管道传输到可写流时暂停可读流
- php - PHP/HTML - 在我的网站上显示不和谐的服务器统计信息
- python - 识别元组中的元素
- c# - Adding records to database with many-to-many relations in ASP.NET Core app with EF Core