【题目描述】

设计并实现最不经常使用(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. 城市代码表mysql

    只有代码: # ************************************************************ # Sequel Pro SQL dump # Version ...

  2. 2018-8-10-win10-uwp-在-Canvas-放一个超过大小的元素会不会被裁剪

    title author date CreateTime categories win10 uwp 在 Canvas 放一个超过大小的元素会不会被裁剪 lindexi 2018-08-10 19:16 ...

  3. write -在一个文件描述符上执行写操作

    概述 #include <unistd.h> ssize_t write(int fd, const void *buf, size_t count); 描述 write 向文件描述符 f ...

  4. Repeater 分页

    1.RepeaterDemo_Page.aspx前台代码 <body> <form id="form1" runat="server"> ...

  5. linux 服务器安装mysql5.6

    1.移除CentOS默认的mysql-libs: whereis mysql 2.为了避免冲突,先移除CenttOS上默认的mysql-libs: yum remove mysql-libs 3.然后 ...

  6. offset系列属性

    offset系列:获取元素的相关的样式属性的值 offsetwidth:获取元素的宽 offsetheight:获取元素的高 offsetleft:获取元素距离左边位置的值 offsettop;获取元 ...

  7. XYIXY.COM短网址在线生成,快速、稳定、永久有效,免费开放网址缩短API接口。

    在PHP中使用API 要在PHP程序中使用API,您必须通过file_get_contents或cURL发送GET请求:两者都是可靠的方法,您可以直接复制下面的代码. <?php /**** S ...

  8. python: 函数递归与尾递归

    如果一个函数在内部调用自己,那么这个函数就是递归函数. 例如一个阶乘函数:fact(n)=n! ,其实可以写成 fact(n)=n x fact(n-1). fact(n) 以递归的方式可以表示为: ...

  9. thinkphp扩展配置

    扩展配置可以支持自动加载额外的自定义配置文件,并且配置格式和项目配置一样. 设置扩展配置的方式如下(多个文件用逗号分隔): // 加载扩展配置文件 'LOAD_EXT_CONFIG' => 'u ...

  10. 修改Chrome的UserAgent

    修改Chrome的UserAgent 直接在chrome商店中搜索user-agent switcher 打开chrome 商店,搜索 user-agent switcher   点击免费, 然后执行 ...