LeetCode:LRU and LFU

文章目录

  • [1. LRU](#1. LRU)
  • [2. LFU](#2. LFU)

1. LRU

Leetcode链接

LRU,即least recently used, 即一个具有固定容量的数据结构,其数据淘汰更新策略,根据最近访问,最久未被访问的元素优先被淘汰。

数据结构设计思路:

  • 链表。通过链表的尾部删除,头部插入,可以非常完美地模拟淘汰更新策略。
  • 哈希表。LRU访问,一般是KV结构,要能够通过key,找到value 。 实际中,哈希表建立的是key 到相应元素在链表中迭代器的映射关系 ,这样不仅可以拿到value,同时可以利用迭代器改变链表元素位置。
  • 整型变量。存储容量。
  • pair类型。存储KV键值对
cpp 复制代码
class LRUCache {
public:
    LRUCache(int capacity) {
        capacity_ = capacity;
    }
    int get(int key) {
        if(hash_.count(key) == 0)
            return -1;
        auto it = hash_[key];
        int val = it->second;
        l_.erase(it);
        l_.push_front({key,val});
        hash_[key] = l_.begin();
        return val;
    } 
    
    void put(int key, int value) {
        if(hash_.count(key)) {
            hash_[key]->second = value;
            (void)get(key);
            return;
        }
        if(capacity_ == 0) {
            int key = l_.back().first;
            l_.pop_back();
            hash_.erase(key);
            capacity_++;
        }
        
        l_.push_front({key,value});
        hash_[key] = l_.begin();
        capacity_--;
    }
    
private:
    using pii = pair<int,int>;
    int capacity_;
    list<pii> l_;
    unordered_map<int,list<pii>::iterator> hash_;
};

2. LFU

Leetcode链接

LFU,即 least frequently used, 即最少频次被使用,同样是有一定淘汰更新策略的固定容量的数据结构。

LFU的淘汰更新策略:

  • 超出容量时,优先淘汰被使用频次最低的元素。
  • 相同频次的元素,优先淘汰最久未被使用的元素。

实际上,如果只看一个频次,那么LFU就是LRU,多个LRU分别对应不同频次,就构成了LFU

所以,我们如下设计LFU数据结构:

  • 哈希表。这个哈希表建立的是频次到具体LRU链表的映射,这样可以通过频次,找到存储相应访问频次元素的链表。
  • 哈希表。该哈希表建立的是key到相应元素链表迭代器的映射,这样可以快速定位元素,而无需找到相应链表后,再遍历。
  • 整型变量。存储容量。
  • 整型变量。存储当前最小频次,这样淘汰时,可以快速通过哈希找到相应链表。
  • 元素数据结构。LRU 中,元素数据结构,简单的pair<int,int> 即可,而LFU 中,还需在 keyvalue 外添加频次,因为这样通过哈希拿到相应元素迭代器后,才能知道这个元素在哪个频次的链表中,进而才能进行更改元素位置的操作。
cpp 复制代码
class LFUCache {
public:
    LFUCache(int capacity) {
        capacity_ = capacity;        
        min_fre_ = 0;
    }
    int get(int key) {
        if(hash_.count(key) == 0)
            return -1;        
        int val = hash_[key]->val_;
        int fre = hash_[key]->fre_;

        list<Node>& l = lists_[fre];
        l.erase(hash_[key]);
        if(l.empty()) {
            lists_.erase(fre);
            if(min_fre_ == fre)
                min_fre_++;
        } 
        lists_[fre + 1].push_front(Node(key,val,fre + 1));
        hash_[key] = lists_[fre + 1].begin();
        return val;
    }
    
    void put(int key, int value) {
        if(hash_.count(key)) {
            hash_[key]->val_ = value;
            (void)get(key);
            return;
        }       
        
        if(capacity_ == 0) {
            list<Node>& l = lists_[min_fre_];
            int key = l.back().key_;
            hash_.erase(key);
            l.pop_back();
            if(l.empty())
                lists_.erase(min_fre_);
            capacity_++;
        }

        lists_[1].push_front(Node(key,value,1));
        min_fre_ = 1;
        hash_[key] = lists_[1].begin();
        capacity_--;
    }    
private:
    struct Node {
        int key_;
        int val_;
        int fre_;

        Node(int key,int val,int fre) {
            key_ = key;
            val_ = val;
            fre_ = fre;
        }
    };
    int capacity_;
    int min_fre_;
    unordered_map<int,list<Node>> lists_;
    unordered_map<int,list<Node>::iterator> hash_;
};
相关推荐
lvwangshu4 分钟前
exBSGS 算法
数学·算法
不会就选b5 分钟前
算法日常・每日刷题--<贪心+大根堆>2
数据结构·算法
码艺-Alimjan6 分钟前
维吾尔语数字转文本
java·javascript·python·算法·go
AI服务老曹9 分钟前
算法任务配置完整流程:明厨亮灶项目从0到1怎么做 | AI视频分析算法实践
人工智能·算法·音视频
hahaha601619 分钟前
HLS高层次综合设计--axi之burst纠偏
开发语言·算法·fpga开发·c#
hans汉斯24 分钟前
【计算机科学与应用】基于联合熵驱动改进麻雀搜索优化VMD的DAS信号去噪方法
深度学习·算法·yolo·软件工程·汉斯出版社
词却28 分钟前
机器学习入门:手写数字识别与算法对比
人工智能·算法·机器学习
张欣-男1 小时前
3分钟理解线性代数
线性代数·算法
白狐_7981 小时前
408 数据结构|外部排序优化:怎么减少时间开销
数据结构·算法
小白说大模型1 小时前
Hermes 全配置指南:从裸版到 AI Agent 天花板
大数据·人工智能·学习·算法·机器学习·数据挖掘