【题目描述】

设计并实现最不经常使用(LFU)缓存的数据结构。它应该支持以下操作:get 和 put。

get(key) - 如果键存在于缓存中,则获取键的值(总是正数),否则返回 -1。

put(key, value) - 如果键不存在,请设置或插入值。当缓存达到其容量时,它应该在插入新项目之前,使最不经常使用的项目无效。在此问题中,当存在平局(即两个或更多个键具有相同使用频率)时,最近最少使用的键将被去除。

进阶:

你是否可以在 O(1) 时间复杂度内执行两项操作?

示例:

LFUCache cache = new LFUCache( 2 /*capacity (缓存容量) */ );

cache.put(1, 1);

cache.put(2, 2);

cache.get(1); // 返回 1

cache.put(3, 3); // 去除 key 2

cache.get(2); // 返回 -1 (未找到key 2)

cache.get(3); // 返回 3

cache.put(4, 4); // 去除 key 1

cache.get(1); // 返回 -1 (未找到 key 1)

cache.get(3); // 返回 3

cache.get(4); // 返回 4

【解题思路】

解题思路见我博客:左神算法进阶班6_1LFU缓存实现

【代码实现】

  

 #pragma once
#include <iostream>
#include <map> using namespace std; class LFUCache {
public:
LFUCache(int capacity) {
this->capacity = capacity;
} int get(int key) {
if (dataMap.find(key) == dataMap.end())//数据不存在
return -;
Node* p = dataMap[key];//找到数据节点
NodeList* h = headMap[p->num];
updataNode(p, h); return p->val;
} void put(int key, int value) {
if (capacity == )
return;
if (dataMap.find(key) != dataMap.end())//已经存在
{
Node* p = dataMap[key];//找到数据节点
NodeList* h = headMap[p->num];//找到头链表节点
p->val = value; updataNode(p, h);//更新数据的使用次数
}
else//如果不存在,则新建
{
if (dataMap.size() >= this->capacity)//容量不足,需要删除数据
deleteData(); Node* p = new Node(key, value, );//使用用一次
dataMap[key] = p;//记录 //将新建节点插入使用1次的子链表中
if (headMap.find() == headMap.end())//当使用1次的子链表不存在
createNode(p, headList);
else
moveNode(p, headMap[]);//插入在使用次数在1的子链表中
}
} private:
struct Node//子链表
{
int key;
int val;
int num;
Node* next;
Node* pre;
Node(int a, int b, int n) :key(a), val(b), num(n), next(nullptr), pre(nullptr) {}
}; struct NodeList//主链表
{
int num;
Node* head;//子链表的头节点
Node* tail;//子链表的尾结点
NodeList* next;
NodeList* pre;
NodeList(int a) :num(a), next(nullptr), pre(nullptr)
{
head = new Node(, , a);//新建一个子链表的头结点
tail = head;
}
}; private:
void getNode(Node*& p, NodeList*& h)//将节点从子链表中取出
{
p->pre->next = p->next;
if (p->next == nullptr)
h->tail = p->pre;
else
p->next->pre = p->pre;
}
void moveNode(Node*& p, NodeList*& q)//将节点向后移动
{
p->next = q->tail->next;
q->tail->next = p;
p->pre = q->tail;
q->tail = p;
}
void deleteNode(int num, NodeList*& h)//删除子链表
{
headMap.erase(num);//从map中删除
h->pre->next = h->next;
if (h->next != nullptr)
h->next->pre = h->pre;
delete h;
h = nullptr;
}
void createNode(Node*p, NodeList*& h)//新建子链表,并插入在主链中
{
NodeList* q = new NodeList(p->num);//新建一个子链表
headMap[p->num] = q;//保存对应的地址 moveNode(p, q);////将节点放入子链表中 //将新子链插入主链表中
q->next = h->next;
if (h->next != nullptr)
h->next->pre = q;
h->next = q;
q->pre = h;
}
void updataNode(Node*& p, NodeList*& h)//更新函数的使用次数
{
int num = p->num;
p->num++;//使用次数+1 //将p从子链表中取出
getNode(p, h); //将该数据向后面移动
if (headMap.find(p->num) == headMap.end())//不存在num+1的节点,那么新建
createNode(p, h);
else
moveNode(p, headMap[p->num]);////将节点放入子链表中 //如果该子链表为空,将该子链表删除,并从map中删除
if (h->head == h->tail)
deleteNode(num, h);
}
void deleteData()//容量不足需要删除
{
NodeList* p = headList->next;
Node* q = p->head->next;//删除子链表排在最前面的数据
if (q == p->tail)//要删除的数据就是最后一个数据,则删除该节点和子链表
deleteNode(q->num, p);
else
{
p->head->next = q->next;
q->next->pre = p->head;
}
dataMap.erase(q->key);//删除记录
delete q;//删除
q = nullptr;
} private:
int capacity;
NodeList* headList = new NodeList();//主链表的头结点
map<int, Node*>dataMap;//key <——> 真实数据节点地址
map<int, NodeList*>headMap;//次数 <——> 链表头节点地址
}; /**
* Your LFUCache object will be instantiated and called as such:
* LFUCache* obj = new LFUCache(capacity);
* int param_1 = obj->get(key);
* obj->put(key,value);
*/ void Test()
{
LFUCache* f = new LFUCache();
f->put(, );
f->put(, );
f->put(, );
f->put(, );
cout << f->get() << endl;
cout << f->get() << endl;
cout << f->get() << endl;
cout << f->get() << endl;
f->put(, );
cout << f->get() << endl;
cout << f->get() << endl;
cout << f->get() << endl;
cout << f->get() << endl;
cout << f->get() << endl; }

力扣算法题—460LFU缓存的更多相关文章

  1. 力扣算法题—146LRU缓存机制

    [题目] 运用你所掌握的数据结构,设计和实现一个  LRU (最近最少使用) 缓存机制.它应该支持以下操作: 获取数据 get 和 写入数据 put . 获取数据 get(key) - 如果密钥 (k ...

  2. 力扣算法题—069x的平方根

    实现 int sqrt(int x) 函数. 计算并返回 x 的平方根,其中 x 是非负整数. 由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去. 示例 1: 输入: 4 输出: 2 示例 ...

  3. 力扣算法题—060第K个排列

    给出集合 [1,2,3,…,n],其所有元素共有 n! 种排列. 按大小顺序列出所有排列情况,并一一标记,当 n = 3 时, 所有排列如下: "123" "132&qu ...

  4. 力扣算法题—050计算pow(x, n)

    #include "000库函数.h" //使用折半算法 牛逼算法 class Solution { public: double myPow(double x, int n) { ...

  5. 力扣算法题—147Insertion_Sort_List

    Sort a linked list using insertion sort. A graphical example of insertion sort. The partial sorted l ...

  6. 力扣算法题—093复原IP地址

    给定一个只包含数字的字符串,复原它并返回所有可能的 IP 地址格式. 示例: 输入: "25525511135" 输出: ["255.255.11.135", ...

  7. 力扣算法题—079单词搜索【DFS】

    给定一个二维网格和一个单词,找出该单词是否存在于网格中. 单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格.同一个单元格内的字母不允许被重复使用. ...

  8. 力扣算法题—052N皇后问题2

    跟前面的N皇后问题没区别,还更简单 #include "000库函数.h" //使用回溯法 class Solution { public: int totalNQueens(in ...

  9. 力扣算法题—051N皇后问题

    #include "000库函数.h" //使用回溯法来计算 //经典解法为回溯递归,一层一层的向下扫描,需要用到一个pos数组, //其中pos[i]表示第i行皇后的位置,初始化 ...

随机推荐

  1. JS对象 四舍五入round() round() 方法可把一个数字四舍五入为最接近的整数。 语法: Math.round(x)

    四舍五入round() round() 方法可把一个数字四舍五入为最接近的整数. 语法: Math.round(x) 参数说明: 注意: 1. 返回与 x 最接近的整数. 2. 对于 0.5,该方法将 ...

  2. vue使用CDN全局安装百度地图

    参考: https://www.zhangshengrong.com/p/O3aA7x5X4E/ 一.在public/index.html中引入cdn <script src="htt ...

  3. js数组方法 slice()和splice()

    说实在我之前都不怎么分的清这个两个函数,因为这两个函数名字那么像,经常我就弄混了,平常使用的时候都先查一下我需要使用的实际是哪个函数.这样不说很浪费时间,但是也是影响了开发效率,所以我决定今天就彻底区 ...

  4. LightOJ 1151 Snakes and Ladders 期望dp+高斯消元

    题目传送门 题目大意:10*10的地图,不过可以直接看成1*100的,从1出发,要到达100,每次走的步数用一个大小为6的骰子决定.地图上有很多个通道 A可以直接到B,不过A和B大小不确定   而且 ...

  5. 如何使用flow进行静态类型检查

    Flow 是 facebook 出品的 JavaScript 静态类型检查⼯具.Vue.js 的源码利⽤了 Flow 做了静态类型检查,所以了解 Flow 有助于我们阅读源码. 为什么⽤ Flow? ...

  6. 关于 第三方接口支付的时候 采用post提交的方式,有两种 一种是通过 curl来进行,一种是通过js当页面加载完后跳转

    这是第一种.通过javascript页面加载完后,对表单采用 post方式提交给 第三方接口----- echo <<<_END<!DOCTYPE html PUBLIC &q ...

  7. Java类加载器浅述

    jdk默认提供了三种类加载器: 1.Bootstrap ClassLoader(引导类加载器): 将<JAVA_HOME>\lib目录下的类库加载到虚拟机内存中,用来加载java的核心库, ...

  8. [JZOJ6344] 【NOIP2019模拟2019.9.7】Huge Counting

    题目 题目大意自己看题去-- 正解 比赛时在刚第二题,所以根本没有时间思考-- 模型可以转化为从\((x_1,x_2,..,x_n)\)出发到\((1,1)\)的方案数模\(2\). 方案数就用有重复 ...

  9. JS基础知识回顾

    回顾 由于 JavaScript 高级还是针对 JavaScript 语言本身的一个进阶学习,所以在开始之前我们先对以前所学过的 JavaScript 相关知识点做一个快速复习总结. 重新介绍 Jav ...

  10. 单独编译和使用webrtc音频降噪模块(附完整源码+测试音频文件)

    单独编译和使用webrtc音频增益模块(附完整源码+测试音频文件) 单独编译和使用webrtc音频回声消除模块(附完整源码+测试音频文件) webrtc的音频处理模块分为降噪ns,回音消除aec,回声 ...