LeetCode题目之腾讯精选练习(50题):LRU缓存机制

题目

运用你所掌握的数据结构,设计和实现一个 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);
        }
    }
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值