美文网首页Swift 集LeetCode
LeetCode - #146 LRU 缓存(Top 100)

LeetCode - #146 LRU 缓存(Top 100)

作者: Swift社区 | 来源:发表于2022-10-19 11:46 被阅读0次

    前言

    本题为 LeetCode 前 100 高频题

    我们社区陆续会将顾毅(Netflix 增长黑客,《iOS 面试之道》作者,ACE 职业健身教练。)的 Swift 算法题题解整理为文字版以方便大家学习与阅读。

    LeetCode 算法到目前我们已经更新到 145 期,我们会保持更新时间和进度(周一、周三、周五早上 9:00 发布),每期的内容不多,我们希望大家可以在上班路上阅读,长久积累会有很大提升。

    不积跬步,无以至千里;不积小流,无以成江海,Swift社区 伴你前行。如果大家有建议和意见欢迎在文末留言,我们会尽力满足大家的需求。

    难度水平:中等

    1. 描述

    请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。

    实现 LRUCache 类:

    • LRUCache(int capacity)正整数 作为容量 capacity 初始化 LRU 缓存
    • int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1
    • void put(int key, int value) 如果关键字 key 已经存在,则变更其数据值 value ;如果不存在,则向缓存中插入该组 key-value 。如果插入操作导致关键字数量超过 capacity ,则应该 逐出 最久未使用的关键字。

    函数 getput 必须以 O(1) 的平均时间复杂度运行。

    2. 示例

    示例 1

    输入
    ["LRUCache", "put", "put", "get", "put", "get", "put", "get", "get", "get"]
    [[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]
    输出
    [null, null, null, 1, null, -1, null, -1, 3, 4]
    
    解释
    LRUCache lRUCache = new LRUCache(2);
    lRUCache.put(1, 1); // 缓存是 {1=1}
    lRUCache.put(2, 2); // 缓存是 {1=1, 2=2}
    lRUCache.get(1);    // 返回 1
    lRUCache.put(3, 3); // 该操作会使得关键字 2 作废,缓存是 {1=1, 3=3}
    lRUCache.get(2);    // 返回 -1 (未找到)
    lRUCache.put(4, 4); // 该操作会使得关键字 1 作废,缓存是 {4=4, 3=3}
    lRUCache.get(1);    // 返回 -1 (未找到)
    lRUCache.get(3);    // 返回 3
    lRUCache.get(4);    // 返回 4
    

    约束条件:

    • 1 <= capacity <= 3000
    • 0 <= key <= 10000
    • 0 <= value <= 10^5
    • 最多调用 2 * 10^5getput

    3. 答案

    class LRUCache {
    
        private let capacity: Int
        private var count = 0
    
        private let head = LRUCacheNode(0, 0)
        private let tail = LRUCacheNode(0, 0)
    
        private var dict = [Int: LRUCacheNode]()
    
        init(_ capacity: Int) {
            self.capacity = capacity
    
            head.next = tail
            tail.pre = head
        }
    
        func get(_ key: Int) -> Int {
            if let node = dict[key] {
                remove(key)
                insert(node)
                return node.val
            }
            return -1
        }
    
        func put(_ key: Int, _ value: Int) {
            if let node = dict[key] {
                node.val = value
                remove(key)
                insert(node)
                return
            }
    
            let node = LRUCacheNode(key, value)
            dict[key] = node
            if count == capacity, let tailKey = tail.pre?.key {
                remove(tailKey)
            }
            insert(node)
        }
    
        private func insert(_ node: LRUCacheNode) {
            dict[node.key] = node
    
            node.next = head.next
            head.next?.pre = node
            node.pre = head
            head.next = node
    
            count += 1
        }
    
        private func remove(_ key: Int) {
            guard count > 0, let node = dict[key] else {
                return
            }
            dict[key] = nil
    
            node.pre?.next = node.next
            node.next?.pre = node.pre
            node.pre = nil
            node.next = nil
    
            count -= 1
        }
    
    }
    
    fileprivate class LRUCacheNode {
    
        let key: Int
        var val: Int
    
        var pre: LRUCacheNode?
        var next: LRUCacheNode?
    
        init(_ key: Int, _ val: Int) {
            self.key = key
            self.val = val
        }
    
    }
    
    • 主要思想:使用链表和哈希映射来构建缓存。
    • 时间复杂度: O(1)
    • 空间复杂度: O(k)

    该算法题解的仓库:LeetCode-Swift

    点击前往 LeetCode 练习

    关于我们

    我们是由 Swift 爱好者共同维护,我们会分享以 Swift 实战、SwiftUI、Swift 基础为核心的技术内容,也整理收集优秀的学习资料。

    后续还会翻译大量资料到我们公众号,有感兴趣的朋友,可以加入我们。

    相关文章

      网友评论

        本文标题:LeetCode - #146 LRU 缓存(Top 100)

        本文链接:https://www.haomeiwen.com/subject/dfmvwrtx.html