首页 > 试题广场 >

设计LFU缓存结构

[编程题]设计LFU缓存结构
  • 热度指数:25698 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
一个缓存结构需要实现如下功能。
  • set(key, value):将记录(key, value)插入该结构
  • get(key):返回key对应的value值
但是缓存结构中最多放K条记录,如果新的第K+1条记录要加入,就需要根据策略删掉一条记录,然后才能把新记录加入。这个策略为:在缓存结构的K条记录中,哪一个key从进入缓存结构的时刻开始,被调用set或者get的次数最少,就删掉这个key的记录;
如果调用次数最少的key有多个,上次调用发生最早的key被删除
这就是LFU缓存替换算法。实现这个结构,K作为参数给出

数据范围:
要求:get和set的时间复杂度都是 ,空间复杂度是


若opt=1,接下来两个整数x, y,表示set(x, y)
若opt=2,接下来一个整数x,表示get(x),若x未出现过或已被移除,则返回-1

对于每个操作2,返回一个答案
示例1

输入

[[1,1,1],[1,2,2],[1,3,2],[1,2,4],[1,3,5],[2,2],[1,4,4],[2,1]],3

输出

[4,-1]

说明

在执行"1 4 4"后,"1 1 1"被删除。因此第二次询问的答案为-1   

备注:

import java.util.*;


public class Solution {
   
    public int[] LFU (int[][] operators, int k) {
        // hashMap和priorityQueue保存,hashMap存调用次数和计时,priorityQueue排序
        HashMap<Integer,Node> count=new HashMap<>();//对key计数,key=operators[i][1],value=node node.count计数 node.time 计时
        HashMap<Integer,int[]> temp=new HashMap<>(); //保存key(operators[i][1])和operators[i]的映射,好方便找出value值
        PriorityQueue<Integer> minHeap=new PriorityQueue<>((o1,o2)->count.get(o1).count.equals(count.get(o2).count)?
            count.get(o1).time.compareTo(count.get(o2).time):count.get(o1).count.compareTo(count.get(o2).count));//优先队列,取count值较小的,count值一致时取time小的
        ArrayList<Integer> res=new ArrayList<>();
        int time=0;
        for(int i=0;i<operators.length;i++){
            if(operators[i][0]==1){
                if(temp.size()==k){
                    int poll=minHeap.poll(); //把调用次数最少的poll掉
                    count.remove(poll);
                    temp.remove(poll);
                }
                //插入temp和count
                temp.put(operators[i][1],operators[i]);
                if(count.containsKey(operators[i][1])){
                    Node node=new Node(count.get(operators[i][1]).count+1,time++);
                    count.put(operators[i][1],node);
                    minHeap.remove(operators[i][1]);
                    minHeap.offer(operators[i][1]);
                }else{
                    Node node1=new Node(1,time++);
                    count.put(operators[i][1],node1);
                    minHeap.offer(operators[i][1]);
                }
            }else if(operators[i][0]==2){
                if(temp.get(operators[i][1])==null){
                    res.add(-1);
                }else{
                    int[] operator=temp.get(operators[i][1]);
                    res.add(operator[2]);
                    if(count.containsKey(operators[i][1])){
                      Node node2=new Node(count.get(operators[i][1]).count+1,time++);
                    count.put(operators[i][1],node2);
                         minHeap.remove(operators[i][1]);
                        minHeap.offer(operators[i][1]);
                    }else{  
                        Node node3=new Node(1,time++);
                        count.put(operators[i][1],node3);
                        minHeap.offer(operators[i][1]);
                    }
                    
                }
            }
        }
        int[] result=new int[res.size()];
        for(int i=0;i<res.size();i++){
            result[i]=res.get(i);
        }
        return result;
    }
}

class Node{
    public Integer count;
    public Integer time;
    
    public Node(Integer count,Integer time){
        this.count=count;
        this.time=time;
    }
}


编辑于 2021-04-14 12:30:06 回复(0)
#
# lfu design
# @param operators int整型二维数组 ops
# @param k int整型 the k
# @return int整型一维数组
#
class Node:
    def __init__(self, key=-1, val=-1):
        self.key = key
        self.val = val
        self.freq = 1
        self.prev = None
        self.next = None

class DLinkedList:
    def __init__(self):
        self.head = Node()
        self.tail = Node()
        self.head.next = self.tail
        self.tail.prev = self.head
        self.size = 0

    def addToHead(self, node):
        node.prev = self.head
        node.next = self.head.next
        self.head.next = node
        node.next.prev = node
        self.size += 1

    def removeNode(self, node):
        node.prev.next = node.next
        node.next.prev = node.prev
        self.size -= 1

    def removeTail(self):
        node = self.tail.prev
        self.removeNode(node)
        return node

from collections import defaultdict
class LFUCache:
    def __init__(self, capacity: int):
        self.cache = {}
        self.freq = defaultdict(DLinkedList)
        self.size = 0
        self.capacity = capacity
        self.min_freq = 0

    def get(self, key: int) -> int:
        if key in self.cache:
            node = self.cache[key]
            self.freq[node.freq].removeNode(node)
            if self.min_freq == node.freq and self.freq[node.freq].size == 0:
                self.min_freq += 1
            node.freq += 1
            self.freq[node.freq].addToHead(node)  
            return node.val
        return -1

    def put(self, key: int, value: int) -> None:
        if self.capacity == 0:
            return
        if key in self.cache:
            node = self.cache[key]
            node.val = value
            self.freq[node.freq].removeNode(node)
            if self.min_freq == node.freq and self.freq[node.freq].size == 0:
                self.min_freq += 1
            node.freq += 1
            self.freq[node.freq].addToHead(node)
        else:
            self.size += 1
            if self.size > self.capacity:
                node = self.freq[self.min_freq].removeTail()
                self.cache.pop(node.key)
                self.size -= 1
            node = Node(key, value)
            self.cache[key] = node
            self.freq[1].addToHead(node)
            self.min_freq = 1




class Solution:
    def LFU(self , operators , k ):
        # write code here
        LFU = LFUCache(k)
        ret = []
        for operator in operators:
            if operator[0] == 1:
                LFU.put(operator[1], operator[2])
            else:
                ret.append(LFU.get(operator[1]))
        return ret

为什么超时了
编辑于 2021-04-23 12:09:45 回复(0)
继看了很多遍题解+调试了半天后终于过了……
struct Node
{
    int key;
    int value;
    Node* pre;
    Node* next;
    int fre;
    Node(int k,int v):key(k),value(v){
        fre=0;
        pre=nullptr;
        next=nullptr;
    }
};
class Solution {
public:
    /**
     * lfu design
     * @param operators int整型vector<vector<>> ops
     * @param k int整型 the k
     * @return int整型vector
     */
    map<int,Node*> k_Node; //key-Node之间的映射
    map<int,Node*> fre_fNode; //频率-该频率对应的链表头结点 之间的映射
    
    int max_fre=0; //当前最大频率
    vector<int> LFU(vector<vector<int> >& operators, int K) {
        if(K==0) {
            return vector<int>();
        }
        vector<int> res;
        int len=0; //当前记录数
        for(vector<int> op:operators) {
            if(op[0]==2) {
                if(k_Node.count(op[1])==0) { //查询的点不存在
                    res.push_back(-1);
                } else { //查询点存在
                    Node* cur=k_Node[op[1]];
                    res.push_back(cur->value);
                    Dele(cur); //将cur从原有的fre链表中删除
                    (cur->fre)++; //调用次数+1
                    Add(cur); //调整该节点,将该节点插入新的频率链表中的位置
                }
            } else {
                //set操作
                int key=op[1],val=op[2];
                Node* cur;
                if(k_Node.count(key)) {
                    cur=k_Node[key];
                    cur->value=val;
                    Dele(cur); //将cur从原有的fre链表中删除
                } else{
                    //该点原来不存在,需要插入
                    if(len==K) {
                        //需删除一条记录
                        int i=1;
                        while(i<=max_fre && fre_fNode[i]->next==fre_fNode[i]) {
                            //因为频率是从1递增的,所以应该是连续的,直接从1开始查找
                            //跳过只有头结点的链表(为空)
                            i++;
                        }
                        Node *del=fre_fNode[i]->next;
                        fre_fNode[i]->next=del->next;
                        del->next->pre=fre_fNode[i];
                        k_Node.erase(del->key);
                        delete del;
                        len--;
                    }
                    cur=new Node(key,val);
                    len++;
                    k_Node[key]=cur;
                }
                (cur->fre)++; //调用次数+1
                 Add(cur); //因为调用次数增加,需要调整在链表中的位置
            }
        }
        return res;
    }
    void Dele(Node* cur) {
        cur->next->pre=cur->pre;
        cur->pre->next=cur->next;
    }
    void Add(Node* cur) {
        if(max_fre<cur->fre) {
            Node* newHead=new Node(0,0);
            newHead->next=newHead;
            newHead->pre=newHead;//生成表示新的频率的双向循环链表头结点
            max_fre++;
            fre_fNode[max_fre]=newHead;
        }
        //加入到新的频率的链表中
        Node *head=fre_fNode[cur->fre];
        cur->pre=head->pre;
        cur->next=head;
        cur->pre->next=cur;
        head->pre=cur;
    }
};


发表于 2021-04-19 11:54:43 回复(3)
import java.util.*;

class Node{
    int k;
    int v;
    int freq;
    Node(int k,int v,int freq){
        this.k = k;
        this.v =v;
        this.freq = freq;
    }
}

class LFUCache {
    HashMap<Integer,Node> hash;
    // 每个链表头部是当前频率最先淘汰的节点,
    HashMap<Integer,LinkedList<Node>> freq_hash;   // key是出现频率,value是双向链表
    int capacity;
    int min_f;                                    // 最小的频率
    int size;

    public LFUCache(int capacity) {
        this.capacity = capacity;
        hash = new HashMap<Integer,Node>();
        freq_hash = new HashMap<Integer,LinkedList<Node>>();
        min_f = 1;
        size = 0;

    }

    public int get(int key) {
        if(hash.get(key) != null){
            Node past = hash.get(key);
            Node newNode = new Node(key,past.v,past.freq+1);
            hash.replace(key,newNode);
            freq_hash.get(past.freq).remove(past);
            if(freq_hash.get(past.freq).size() == 0){
                freq_hash.remove(past.freq);
                if(min_f == past.freq)
                    ++min_f;
            }
            if(freq_hash.get(newNode.freq) == null){
                freq_hash.put(newNode.freq,new LinkedList<>());
            }
            freq_hash.get(newNode.freq).addLast(newNode);
            return past.v;
        }else
            return -1;

    }

    public void put(int key, int value) {
        if(capacity == 0)
            return;
        if(hash.get(key) == null){
            Node newNode = new Node(key,value,1);
            if(size == capacity){
                Node rm = freq_hash.get(min_f).removeFirst();
                if(freq_hash.get(min_f).size() == 0)
                    freq_hash.remove(min_f);
                hash.remove(rm.k);
                --size;
            }
            hash.put(key,newNode);
            if(freq_hash.get(1) == null){
                freq_hash.put(1,new LinkedList<>());
            }
            freq_hash.get(1).addLast(newNode);
            ++size;
            min_f = 1;
        }else{
            Node past = hash.get(key);
            Node newNode = new Node(key,value,past.freq+1);

            hash.replace(key,newNode);

            freq_hash.get(past.freq).remove(past);
            if(freq_hash.get(past.freq).size() == 0){
                freq_hash.remove(past.freq);
                if(min_f == past.freq)
                    ++min_f;
            }
            if(freq_hash.get(newNode.freq) == null){
                freq_hash.put(newNode.freq,new LinkedList<>());
            }
            freq_hash.get(newNode.freq).addLast(newNode);
        }
    }
}

public class Solution {
    
    public int[] LFU (int[][] operators, int k) {
        LFUCache lfu = new LFUCache(k);
        ArrayList<Integer> data = new  ArrayList<Integer>();
        int row = operators.length;
        for(int i = 0;i < row;++i){
            int op = operators[i][0];
            int key = operators[i][1];
            if(op == 1)
                lfu.put(key,operators[i][2]);
            if(op == 2)
                data.add(lfu.get(key));
        }
        int [] res = new int[data.size()];
        for(int i = 0;i < data.size();++i)
            res[i] = data.get(i);
        return res;
        
        
    }
}

发表于 2021-04-04 11:07:43 回复(0)
1. 用一个unordered_map作为缓存,用来判断key在不在缓存里面
2. 用一个std::set对缓存中的所有元素按照访问频率、访问时间从小到达排序,因为std::set的底层是红黑树结构,是一个有序的数据结构
3. 需要注意的是在定义set的排序函数,operator<必须被重载为const类型
#include <unordered_map>

struct Node {
    int key, value;
    int frequency, visit_time;
    Node() { }
    Node(int k, int v, int f, int t): key(k), value(v), frequency(f), visit_time(t) { }
    
    // (*this).operator<(node)相当于operator<((*this), node)
    bool operator<(const Node& node) const{
        if(this->frequency == node.frequency) {
            return this->visit_time < node.visit_time;
        }
        else {
            return this->frequency < node.frequency;
        }
    }
};

class Solution {
public:
    int sys_time;            // 代表系统时间
    int capacity;            // 代表缓存容量
    std::set<Node> sorted_tree;
    std::unordered_map<int, Node> cache;
    
    void init(int _capacity) {
        sys_time = 0;
        capacity = _capacity;
    }
    
    int get(int key) {
        sys_time++;
        if(capacity == 0) {
            return -1;
        }
        auto it = cache.find(key);
        if(it == cache.end()) {
            return -1;
        }
        Node node = it->second;
        // 从set中删除该结点
        sorted_tree.erase(node);
        
        node.visit_time = sys_time;    // 修改访问时间
        node.frequency++;              // 修改访问次数
        
        cache[key] = node;
        sorted_tree.insert(node);
        
        return node.value;
    }
    
    void set(int key, int value) {
        sys_time++;
        if(capacity == 0) {
            return;
        }
        auto it = cache.find(key);
        if(it == cache.end()) {
            // 缓存已满,需要删除最少被访问的元素
            if(cache.size() == capacity) {
                auto delNode = sorted_tree.begin();
                cache.erase(delNode->key);
                sorted_tree.erase(delNode);
            }
            Node newNode(key, value, 1, sys_time);
            cache[key] = newNode;
            sorted_tree.insert(newNode);
        }
        else {
            Node node = it->second;
            sorted_tree.erase(node);
            node.value = value;
            node.frequency++;
            node.visit_time = sys_time;
            cache[key] = node;
            sorted_tree.insert(node);
        }
    }
    
    /**
     * lfu design
     * @param operators int整型vector<vector<>> ops
     * @param k int整型 the k
     * @return int整型vector
     */
    vector<int> LFU(vector<vector<int> >& operators, int k) {
        vector<int> ans;
        // 初始化
        init(k);
        
        for(auto& op: operators) {
            int operate = op[0];
            if(operate == 1) {
                set(op[1], op[2]);
            }
            else if(operate == 2) {
                ans.push_back(get(op[1]));
            }
            else {
                continue;
            }
        }
        return ans;
    }
};


发表于 2020-09-18 10:02:17 回复(3)
有点小复杂,用一个HashMap存储key和value。
import java.util.*;


public class Solution {
    class Node{
    int key;
    int value;
    int frep=1;
    public Node(){
    }
    public Node(int key,int value){
        this.key = key;
        this.value = value;
    }
  }
    Map<Integer,Node> cache;//存储数据
    Map<Integer, LinkedHashSet<Node>> freqMap;//存储频率对应的双向链表
    int size;//当前已经存储的数据个数
    int capacity;//存储容量
    int min;//当前最小的频率
        
        
    /**
     * lfu design
     * @param operators int整型二维数组 ops
     * @param k int整型 the k
     * @return int整型一维数组
     */
    public int[] LFU (int[][] operators, int k) {
        // write code here
        this.capacity = k;
        cache = new HashMap<>();
        freqMap = new HashMap<>();
        
        List<Integer> out = new ArrayList<>();
        for(int i=0;i < operators.length;i++){
            if(operators[i][0] == 1){
                put(operators[i][1],operators[i][2]);
            }
            else if(operators[i][0] == 2){
                out.add(get(operators[i][1]));
            }
        }
        int[] res = new int[out.size()];
        for(int i=0;i < out.size();i++){
            res[i] = out.get(i);
        }
        return res;
    }
        //get函数,先获取节点,如果节点为空,则返回-1,不为空则更新频率再返回节点值
    public int get(int key){
        Node node = cache.get(key);
        if(node == null){
            return -1;
        }
        freqInc(node);
        return node.value;
    }
    //put函数
    public void put(int key,int value){
        if(capacity == 0) return;
        Node node = cache.get(key);
        if(node != null){
            node.value = value;
            freqInc(node);
        }
        else {
            //如果当前存储满了,就删除一个节点
            if(size == capacity){
                Node deadNode = removeNode();
                cache.remove(deadNode.key);
                size--;
            }
            //添加新的节点
            node = new Node(key,value);
            cache.put(key,node);//节点加入存储的hashmap
            addNode(node);
            size++;//更新当前存储容量
        }
    }
    //更新频率函数
    public void freqInc(Node node){
        //将节点从原频率的链表中删除,并更新当前最小的频率
        int frep = node.frep;
        LinkedHashSet<Node> set = freqMap.get(frep);
        set.remove(node);
        //如果当前频率是最小频率,并且移除该节点后,最小频率的链表为空则更新最小频率,为当前频率加一
        if(frep == min && set.size() == 0){
            min = frep + 1;
        }
        //更新节点的频率,并且加入到对应的频率链表
        node.frep++;
        LinkedHashSet<Node> newSet = freqMap.computeIfAbsent(frep + 1, k -> new LinkedHashSet<>());
        //如果不存在当前频率对应的频率链表,则新建一个
        newSet.add(node);
    }
    //在链表中删除节点函数,删除频率最小,并且最久没使用的节点
    public Node removeNode(){
        LinkedHashSet<Node> set = freqMap.get(min);
        Node deadNode = set.iterator().next();//删除set中的第一个元素,就是最先加入的那个
        set.remove(deadNode);
        return deadNode;
    }
    //在链表中添加节点函数
    public void addNode(Node node){
        LinkedHashSet<Node> set = freqMap.computeIfAbsent(1, k -> new LinkedHashSet<>());
        set.add(node);
        min = 1;//只要添加了新节点最小频率就是1,min变化还会发生在更新频率的时候
    }
}


发表于 2020-08-31 17:52:17 回复(1)
纯Map实现(纯粹是因为链表太长了不想看),在LRU的基础上改的,仅供参考。
/**
 * @param {number} capacity
 */
var Solution = function(capacity) {
    // write code here
    this.max = capacity;
    this.map = new Map();//保存数据的map
    this.nummap = new Map();//记录次数的map
};

/** 
 * @param {number} key
 * @return {number}
 */
Solution.prototype.get = function(key) {
    // write code here
    if(!this.map.has(key)) return -1;
    else {
        let value = this.map.get(key);
        let cnt = this.nummap.get(key)+1;
        //每访问一次重新加入,方便后续次数相同的情况找到最早访问的
        this.nummap.delete(key);
        this.nummap.set(key,cnt);
        return value;
    }
};

/** 
 * @param {number} key 
 * @param {number} value
 * @return {void}
 */
Solution.prototype.set = function(key, value) {
    // write code here
    if(this.map.has(key)){
        this.map.set(key,value);
        this.nummap.set(key,this.nummap.has(key)?this.nummap.get(key)+1:1);
     }
    else{
        if(this.map.size == this.max){
            let keys = Array.from(this.nummap.keys());
            let cnt = Infinity,tmp;
            //找到次数最小并且访问最早的
            for(let item of keys){
                if(this.nummap.get(item)<cnt){cnt=this.nummap.get(item);tmp=item;}
            }
            //同时删掉两个map中该key的数据
            this.map.delete(tmp);
            this.nummap.delete(tmp);
            
            this.map.set(key,value);
            this.nummap.set(key,this.nummap.has(key)?this.nummap.get(key)+1:1);
        }else{
            this.map.set(key,value);
            this.nummap.set(key,this.nummap.has(key)?this.nummap.get(key)+1:1);
        }
    }
};

/**
 * lfu design
 * @param operators int整型二维数组 ops
 * @param k int整型 the k
 * @return int整型一维数组
 */
function LFU( operators ,  k ) {
    // write code here
    let obj = new Solution(k);
    let res = [];
    for(let i=0;i<operators.length;i++){
        let op = operators[i];
        //进行set
        if(op[0]==1){
            obj.set(op[1],op[2]);
        }
        //进行get
        else{
            res.push(obj.get(op[1]));
        }
    }
    return res;
}
module.exports = {
    LFU : LFU
};



发表于 2022-10-30 19:11:04 回复(1)
通过
#include <stdio.h>
#include <string.h>
struct ListTable{
    int key;
    int value;
    struct ListTable *last;
    struct ListTable *next;
    int count;
};
typedef struct List{
    int  capacity;
    int  NodeNum;
    //struct ListTable *HashTable[2000000001];
    struct ListTable *head,*end;
} Solution;

struct ListTable* searchMinCountNode(Solution* obj) {
    struct ListTable* p;
    int Min=100001;
    p = obj->head;
    while(p!=NULL) {
        if(Min > p->count)
            Min = p->count;
        p = p->next;
    }
    p = obj->head;
    while(p->next!=NULL) {
        if(Min == p->count)
            return p;
        p = p->next;
    }
    return obj->head;
}

struct ListTable* searchNode(Solution* obj, int key) {
    struct ListTable* p = obj->head;
    while(p!=NULL) {
        if(p->key == key)
            return p;
        p = p->next;
    }
    return NULL;
}

void SubNode(Solution* obj, int key, struct ListTable* HashTable) {
    if(HashTable==obj->head){
        obj->head = obj->head->next;
        obj->head->last = NULL;
    }
    else  if(HashTable==obj->end) {
        obj->end = HashTable->last;
        obj->end->next = NULL;
    }
    else {
        HashTable->last->next = HashTable->next;
        HashTable->next->last = HashTable->last;
    }
    HashTable->next = NULL;
    HashTable->last = NULL;
}

void AddEndNode(Solution* obj, int key, int value, struct ListTable* HashTable) {
    obj->end->next = HashTable;
    HashTable->last = obj->end;
    HashTable->next = NULL;
    obj->end = HashTable;
    HashTable->key = key;
    HashTable->value = value;
}

Solution* SolutionCreate(int capacity) {
    int i;
    Solution *res;
    res = (Solution*)malloc(sizeof(Solution));
    res->capacity = capacity;
    res->NodeNum = 0;
    res->head = NULL;
    res->end = NULL;
    return res;
}

int SolutionGet(Solution* obj, int key) {
    struct ListTable* HashTable = searchNode(obj, key);
    if(HashTable == NULL) 
        return -1;
    if(HashTable!=obj->end) {
        SubNode(obj, key, HashTable);
        AddEndNode(obj, key, HashTable->value, HashTable);
    }
    HashTable->count++;
    return HashTable->value; 
}

void SolutionPut(Solution* obj, int key, int value) {
    struct ListTable* HashTable = searchNode(obj, key);
    if(obj->head == NULL) {
        obj->head = (struct ListTable*)malloc(sizeof(struct ListTable));
        obj->end = obj->head;
        obj->head->key = key;
        obj->head->value = value;
        obj->head->last = NULL;
        obj->head->next = NULL;
        obj->head->count = 1;
        obj->NodeNum = 1;
    }
    else {
        if(HashTable == NULL) {
            struct ListTable* NewNode;
            NewNode = (struct ListTable*)malloc(sizeof(struct ListTable));
            obj->NodeNum++;
            NewNode->count = 1;
            AddEndNode(obj, key, value, NewNode);
        }   
        else {
            if(HashTable == obj->end){
                HashTable->value = value;
                HashTable->count++;
            }
            else {
                SubNode(obj, key, HashTable);
                AddEndNode(obj, key, value, HashTable);
                HashTable->count++;
            }
        }
            
        if(obj->NodeNum > obj->capacity) {
            struct ListTable* p = obj->head;
            p = searchMinCountNode(obj);
            SubNode(obj, p->key, p);
            free(p);
            obj->NodeNum--;
        }
    }
}

void SolutionFree(Solution* obj) {
    int i;
    struct ListTable* p = obj->head;
    for(i=0; i<obj->NodeNum-1; i++) {
        struct ListTable* last=p;
        p = p->next;
        free(last);
    }
    free(obj);
}

int* LFU(int** operators, int operatorsRowLen, int* operatorsColLen, int k, int* returnSize ) {
    Solution *obj = SolutionCreate(k);
    int i, *res;
    res = (int*)malloc(100000*sizeof(int));
    (*returnSize) = 0;
    for(i=0; i<operatorsRowLen; i++) {
        if(operators[i][0]==1) 
            SolutionPut(obj, operators[i][1], operators[i][2]);
        else 
            res[(*returnSize)++] = SolutionGet(obj, operators[i][1]);
    }
    SolutionFree(obj);
    return res;
}

编辑于 2024-03-29 22:06:12 回复(0)
用调表更好,但是写调表要花好多时间,就用tree map吧。。
#include <algorithm>
#include <map>
#include <unordered_map>
struct Node {
    int key;
    int data;
    int accessCount{};
    Node* prev{};
    Node* next{};
    Node(int key, int data) : key(key), data(data) {}
};

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * lfu design
     * @param operators int整型vector<vector<>> ops
     * @param k int整型 the k
     * @return int整型vector
     */
    vector<int> LFU(vector<vector<int> >& operators, int k) {
        // write code here
        this->cap = k;
        vector<int> result;
        for (auto const &item : operators) {
            if (item[0] == 1) {
                set(item[1], item[2]);
            } else if (item[0] == 2) {
                result.push_back(get(item[1]));
            }
        }

        return result;
    }

    void set(int key, int data) {
        auto it = cache.find(key);
        if (it != cache.end()) {
            auto *node = it->second;
            if (node->data != data) {
                node->data = data;
            }
            removeFromLFU(node);
            node->accessCount += 1;
            addToLFU(node);
            return;
        }

        if (cache.size() >= cap) {
            auto *rmNode = removeCandidate();
            cache.erase(rmNode->key);
            delete rmNode;
        }

        auto *node = new Node(key, data);
        cache[key] = node;
        node->accessCount += 1;
        addToLFU(node);
    }

    int get(int key) {
        auto it = cache.find(key);
        if (it == cache.end()) {
            return -1;
        }

        auto *node = it->second;
        removeFromLFU(node);
        node->accessCount += 1;
        addToLFU(node);

        return node->data;
    }

    Node* removeFromLFU(Node *node) {
        auto it = lfuCache.find(node->accessCount);
        assert(it != lfuCache.end());
        return removeFromLFU(it, node);
    }

    Node* removeFromLFU(map<int, pair<Node*, Node*>>::iterator &it, Node *node) {
        auto *prev = node->prev;
        auto *next = node->next;
        if (prev != nullptr) {
            prev->next = next;
        } else {
            it->second.first = next;
        }
        if (next != nullptr) {
            next->prev = prev;
        } else {
            it->second.second = prev;
        }

        if (it->second.first == nullptr) {
            lfuCache.erase(it->first);
        }

        node->prev = node->next = nullptr;
        return node;
    }

    void addToLFU(Node *node) {
        auto it = lfuCache.find(node->accessCount);
        if (it == lfuCache.end()) {
            //lfuCache.emplace(make_pair(node->accessCount, make_pair(node, node)));
            lfuCache[node->accessCount] = make_pair(node, node);
            return;
        }

        node->next = it->second.first;
        it->second.first->prev = node;
        it->second.first = node;
    }

    Node* removeCandidate() {
        auto it = lfuCache.lower_bound(INT_MIN);
        assert(it != lfuCache.end());
        auto *node = removeFromLFU(it, it->second.second);
        return node;
    }

    int cap;
    unordered_map<int, Node*> cache;
    map<int, pair<Node*, Node*>> lfuCache; // a skip-list should be better, but coding for a skip-list takes lots of time
};


发表于 2023-09-22 18:13:27 回复(0)
设计一个LFUCache类用于实现set和get操作,在LFUCache类内使用两个unordered_map,使得set和get操作的时间复杂度为O(1),具体代码如下:
class LFUCache {
public:
    LFUCache(int capacity) {
        cap = capacity;
    }

    int get(int key) {
        if (!keyToIdx.count(key)) return -1;

        /*更新freToKey*/
        int fre = keyToIdx[key]->fre;
        int val = keyToIdx[key]->val;
        // 1. 删除原结点
        freToKey[fre].erase(keyToIdx[key]);
        if (freToKey[fre].empty()) freToKey.erase(fre);
        if (minFre == fre && !freToKey.count(fre)) {
            minFre = fre + 1;
        }
        // 2. 增加结点
        freToKey[fre + 1].push_front(Node(key, val, fre + 1));
        // 3. 重新修改指向
        keyToIdx[key] = freToKey[fre + 1].begin();

        // 返回
        return val;
    }

    void set(int key, int value) {
        if (cap == 0) return;

        // LFU缓存中已存在key
        if (keyToIdx.count(key)) {
            get(key);
            keyToIdx[key]->val = value;
            return;
        }

        if (keyToIdx.size() == cap) {
            // LFU缓存容量满,删除频率最小的结点
            int k = freToKey[minFre].back().key;
            freToKey[minFre].pop_back();
            if (freToKey[minFre].empty()) freToKey.erase(minFre);

            keyToIdx.erase(k);
        }
        // 插入新结点
        freToKey[1].push_front(Node(key, value, 1));
        keyToIdx[key] = freToKey[1].begin();
        minFre = 1;
    }

private:
    struct Node {
        int key, val, fre;
        Node() = default;
        Node(int k, int v, int f): key(k), val(v), fre(f){}
    };
    int cap, minFre;
    unordered_map<int, list<Node>::iterator> keyToIdx;
    unordered_map<int, list<Node>> freToKey;
};


class Solution {
public:
    /**
     * lfu design
     * @param operators int整型vector<vector<>> ops
     * @param k int整型 the k
     * @return int整型vector
     */
    vector<int> LFU(vector<vector<int> >& operators, int k) {
        // write code here
        LFUCache lfu(k);
        vector<int> ans;
        for (auto & it : operators) {
            if (it[0] == 1) {
                lfu.set(it[1], it[2]);
            } else {
                ans.push_back(lfu.get(it[1]));
            }
        }
        
        return ans;
    }
};


发表于 2022-05-02 11:45:40 回复(0)
class Solution {
public:
    /**
     * lfu design
     * @param operators int整型vector<vector<>> ops
     * @param k int整型 the k
     * @return int整型vector
     */
    template<class T>
    class Priority{
        public:
        priority_queue<T,vector<T>,greater<T>>  g_q;
        priority_queue<T,vector<T>,greater<T>>  l_q;
        void push(T a){
            g_q.push(a);
        }
        void erase(T b){
            l_q.push(b);
        }
        T top(){
             while(l_q.size()&& g_q.size()&&l_q.top()<=g_q.top()){
                if(l_q.top()==g_q.top()){
                    g_q.pop();
                }
                l_q.pop();
            }
            return g_q.top();
        }
        void pop(){
           while(l_q.size()&& g_q.size()&&l_q.top()<=g_q.top()){
                if(l_q.top()==g_q.top()){
                    g_q.pop();
                }
                l_q.pop();
            }
            g_q.pop();
        }

    };
    class LFU_ {
        public:
        Priority<pair<pair<int,int>,pair<int,int>>>  q;
        unordered_map<int ,pair<pair<int,int>,pair<int,int>>> m;
        int size;
        LFU_(int s):size(s){

        };
        int time=0;
        int get(int x){
            if(m.find(x)==m.end()){
                return -1;
            }
            else{
                auto &p=m[x];
                q.erase(p);
                p.first.first+=1;
                p.first.second=time++;
                q.push(p);
                return p.second.second;
            }
        }
        void set(int x,int y){
            if(m.find(x)==m.end()){
               if(size==0){
                   auto p=q.top();
                   q.pop();
                   m.erase(p.second.first);
                   pair<pair<int,int>,pair<int,int>> b={{0,time++},{x,y}};
                   m[x]=b;
                   q.push(b);
               }
               else{
                   pair<pair<int,int>,pair<int,int>> b={{0,time++},{x,y}};
                   m[x]=b;
                   q.push(b);
                   size--;
               }
            }else{
                auto &p=m[x];
                q.erase(p);
                p.first.first+=1;
                p.first.second=time++;
                p.second.second=y;
                q.push(p);
            }
        }
    };
    vector<int> LFU(vector<vector<int> >& operators, int k) {
        // write code here
        LFU_ tmp(k);
        vector<int> out;
        for(auto i:operators){
            if(i[0]==1){
                tmp.set(i[1],i[2]);
            }
            else{
                int o=tmp.get(i[1]);
                out.push_back(o);
            }
        }
        return out;
    }
    
    

};
使用两个优先队列实现插入和删除
发表于 2022-04-16 19:48:03 回复(0)
用一个 LinkedHashMap进行保存, key为待存数据key, value整型数组 为  值和出现次数
import java.util.*;


public class Solution {
    /**
     * lfu design
     * @param operators int整型二维数组 ops
     * @param k int整型 the k
     * @return int整型一维数组
     */
    public int[] LFU (int[][] operators, int k) {
        // write code here
        Map<Integer, Integer[]> map = new LinkedHashMap<>(k);
        List<Integer> res = new ArrayList<>();
        for(int [] ops: operators) {
            if(ops[0] == 1) {
                // set
                set(map, ops[1], ops[2], k);
            }else if(ops[0] == 2) {
                // get
                res.add(get(map, ops[1]));
            }
        }
        
        return res.stream().mapToInt(x -> x).toArray();
    }
    
    // set
    private void set(Map<Integer, Integer[]> map, int key, int val, int cap) {
        if(map.size() == cap) {
            remove(map);
        }
        Integer[] value = map.get(key);
        if(value != null) {
            // exists
            map.put(key, new Integer[]{val, value[1] + 1});
        }else {
            map.put(key, new Integer[]{val, 1});
        }
    }
    
    // get
    private Integer get(Map<Integer, Integer[]> map, int key) {
        Integer[] value = map.get(key);
        if(value == null) {
            return -1;
        }else {
            map.put(key, new Integer[]{value[0], value[1] + 1});
            return value[0];
        }
    }
    
    // remove
    private void remove(Map<Integer, Integer[]> map) {
        int key = 0,  min = Integer.MAX_VALUE;
        for(Map.Entry<Integer, Integer[]> entry: map.entrySet()) {
            if(entry.getValue()[1] < min) {
                min = entry.getValue()[1];
                key = entry.getKey();
            }
        }
        map.remove(key);
    }
}


编辑于 2021-03-23 17:02:07 回复(0)

LFU与LRU相似,只不过当容量超出时,需要删除最近最不常使用。因此使用map来记录每个频率对应的LRU的链表,则删除元素时,只需要删除队头元素即可。

import java.util.*;
public class Solution {
    class Node {
        int key, value, frequency;
        Node(int k, int v) {
            this.key = k;
            this.value = v;
            this.frequency = 1;
        }
    }
    private Map cache;
    private Map> frequencyMap;  // 根据频率记录 每个频率对应的LRU 链表
    private int capacity;
    private int minFrequency;
    public int[] LFU(int[][] operators, int k) {
        this.capacity = k;
        this.cache = new HashMap();  // 记录所有节点
        this.frequencyMap = new HashMap();
        List result = new ArrayList();
        for (int[] operator : operators) {
            if (operator[0] == 1) {
                this.set(operator[1], operator[2]);
            } else if (operator[0] == 2) {
                Node node = get(operator[1]);
                result.add(node == null ? -1 : node.value);
            }
        }
        return result.stream().mapToInt(Integer::intValue).toArray();
    }
    private void set(int key, int value) {
        if (capacity == 0) return;
        if (cache.containsKey(key)) {
            Node node = cache.get(key);
            node.value = value;  // 更新一下value
            this.get(key); // 调用一下get 更新频率 逻辑写在 get里面了
            return;
        }
        if (cache.size() >= capacity) {
            evictLFU();  // 删除最少 最常不使用
        }
        Node newNode = new Node(key, value);
        this.cache.put(key, newNode);
        this.frequencyMap.computeIfAbsent(1, k -> new LinkedHashSet()).add(newNode);
        minFrequency = 1;
    }
    private Node get(int key) {
        if (!this.cache.containsKey(key)) return null;
        Node node = cache.get(key);
        int freq = node.frequency;
        this.frequencyMap.get(freq).remove(node);
        if (this.frequencyMap.get(freq).isEmpty()) {
            this.frequencyMap.remove(freq);
            if (minFrequency == freq) { // 更新最小频率
                minFrequency++;
            }
        }
        node.frequency++;
        this.frequencyMap.computeIfAbsent(node.frequency,
                                     k -> new LinkedHashSet()).add(node);
        return node;
    }
    private void evictLFU() {
        LinkedHashSet nodes = this.frequencyMap.get(minFrequency);
        Node nodeToEvict = nodes.iterator().next();
        nodes.remove(nodeToEvict);
        if (nodes.isEmpty()) {
            this.frequencyMap.remove(minFrequency);
        }
        this.cache.remove(nodeToEvict.key);
    }
}
发表于 2024-11-04 15:39:23 回复(0)
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
# lfu design
# @param operators int整型二维数组 ops
# @param k int整型 the k
# @return int整型一维数组
#
class Solution:
    def LFU(self, operators: List[List[int]], k: int) -> List[int]:
        # write code here
        self.capacity = k
        self.dic = {}
        self.times = {}
        ans = []

        def pop():
            t = min(self.times)
            e = self.times[t].pop(0)
            if not self.times[t]:
                del self.times[t]
            return e

        def change(key: int, t: int):
            self.times[t].remove(key)
            if not self.times[t]:
                del self.times[t]
            if (t + 1) in self.times:
                self.times[t + 1].append(key)
            else:
                self.times[t + 1] = [key]

        def insert(key: int):
            if 1 in self.times:
                self.times[1].append(key)
            else:
                self.times[1] = [key]

        def get(key: int) -> int:
            if key in self.dic:
                change(key, self.dic[key]["times"])
                self.dic[key]["times"] += 1
                return self.dic[key]["val"]
            else:
                return -1

        def set(key: int, value: int) -> None:
            if key in self.dic:
                self.dic[key]["val"] = value
                change(key, self.dic[key]["times"])
                self.dic[key]["times"] += 1
            else:
                if len(self.dic) == self.capacity:
                    del self.dic[pop()]
            self.dic[key] = {"val": value, "times": 1}
            insert(key)

        for op in operators:
            if op[0] == 1:
                set(op[1], op[2])
            else:
                ans.append(get(op[1]))
        return ans

发表于 2024-07-17 17:12:50 回复(0)
没读懂
operators里面的参数代表啥意思,怎么读出现两个参数,写有三个参数
发表于 2024-07-14 01:20:18 回复(0)
import java.util.*;


public class Solution {
    private class Frequency {
        int key; // 键
        int val; // 值
        int count = 0; // 访问频次
        int time; //上一次操作时间
        Frequency(int key, int val, int time) {
            this.key = key;
            this.val = val;
            this.time = time;
        }
    }
    public int[] LFU (int[][] operators, int k) {
        ArrayList<Integer> res = new ArrayList<Integer>(); // 用于记录返回结果
        int time = 0; // 每次操作都累加, 用于记录时间
        PriorityQueue<Frequency> queue = new PriorityQueue<Frequency>
        (new Comparator<Frequency>() {
            public int compare(Frequency o1, Frequency o2) {
                return o1.count == o2.count ? o1.time - o2.time : o1.count - o2.count;
            }
        }); // 小根堆
        HashMap<Integer, Frequency> map = new HashMap<Integer, Frequency>
        (k); // hash表,用于存放键值对
        for (int i = 0; i < operators.length; i++) {
            time++; // 时间计数
            if (operators[i][0] == 1) { // set操作
                int key = operators[i][1];
                int val = operators[i][2];
                if (map.containsKey(key)) { // 待加入的key已存在
                    Frequency item = map.get(key);
                    item.count++;
                    item.val = val;
                    item.time = time;
                    // refresh(queue); // 移除此行,不再调用 refresh 方法
                    queue.remove(item); // 直接从队列中移除旧元素
                    queue.add(item); // 根据更新后的优先级重新插入
                } else { // 待加入的key不存在
                    if (map.size() >= k) { // 超出容量限制
                        Frequency item = queue.poll(); // 队首出队
                        int oldkey = item.key;
                        map.remove(oldkey); // 删除LFU
                    }
                    Frequency item = new Frequency(key, val, time); // 新元素入队
                    map.put(key, item);
                    queue.add(item);
                }

            } else if (operators[i][0] == 2) { // get操作
                int key = operators[i][1];
                if (map.containsKey(key)) {
                    Frequency item = map.get(key);
                    item.count++;
                    item.time = time;
                    // refresh(queue); // 移除此行,不再调用 refresh 方法
                    queue.remove(item); // 直接从队列中移除旧元素
                    queue.add(item); // 根据更新后的优先级重新插入
                    int resVal = item.val;
                    res.add(resVal);
                } else {
                    res.add(-1);
                }
            }
        }
        int[] ans = new int[res.size()]; // 收集结果
        for (int i = 0; i < res.size(); i++) {
            ans[i] = res.get(i);
        }
        return ans;
    }
    /**
    当您将一个对象放入 PriorityQueue 后,如果在外部直接修改该对象的属性,导致其优先级发生变化,队列并不会自动调整。PriorityQueue 仅在元素添加到队列时和进行队列操作(如 add、offer、poll、remove 等)时依据提供的 Comparator 确定元素的优先级。
     */
    /**
    在 refresh(PriorityQueue<Frequency> queue) 方法中,您试图通过将队首元素出队后再重新入队的方式来刷新队列,使其根据元素更新后的优先级重新排序。然而,这种方式并不能达到预期效果,因为:

    出队操作(queue.poll())仅移除了队首元素,但并未更新其优先级。
    入队操作(queue.add(item))会根据 item 当前的优先级重新插入,但可能由于该元素优先级未更新,其位置并没有变化。
     */
    public void refresh(PriorityQueue<Frequency> queue) {
        if (!queue.isEmpty()) {
            Frequency item = queue.poll();
            queue.add(item);
        }
    }
}

编辑于 2024-04-23 14:58:57 回复(0)
public class Solution {
    private int capacity = 0;
    private Map<Integer, Integer> cacheMap = new HashMap<>();
    private Map<Integer, Integer> keyFreqMap = new HashMap<>();
    private Map<Integer, Set<Integer>> freqKeysMap = new TreeMap<>();

    private void set(int key, int value) {
        Integer cacheValue = cacheMap.get(key);
        cacheMap.put(key, value);
        if (cacheValue == null) {
            if (cacheMap.size() > capacity) {
                Map.Entry<Integer, Set<Integer>> minimumFreqEntry =
                    freqKeysMap.entrySet().iterator().next();
                Integer minimumFreqKey = minimumFreqEntry.getValue().iterator().next();
                remove(minimumFreqKey);
            }
        }
        updateFreq(key);
    }

    private int get(int key) {
        Integer cacheValue = cacheMap.get(key);
        if (cacheValue != null) {
            updateFreq(key);
            return cacheValue;
        } else {
            return -1;
        }
    }

    private void remove(int key) {
        cacheMap.remove(key);
        Integer freq = keyFreqMap.remove(key);
        Set<Integer> freqKeys = freqKeysMap.get(freq);
        freqKeys.remove(key);
        if (freqKeys.isEmpty()) {
            freqKeysMap.remove(freq);
        }
    }

    private void updateFreq(int key) {
        Integer freq = keyFreqMap.remove(key);
        if (freq != null) {
            keyFreqMap.put(key, freq + 1);
            Set<Integer> freqKeys = freqKeysMap.get(freq);
            freqKeys.remove(key);
            if (freqKeys.isEmpty()) {
                freqKeysMap.remove(freq);
            }
            freqKeysMap.computeIfAbsent(freq + 1, a -> new LinkedHashSet<>()).add(key);
        } else {
            keyFreqMap.put(key, 1);
            freqKeysMap.computeIfAbsent(1, a -> new LinkedHashSet<>()).add(key);
        }
    }

    public int[] LFU(int[][] operators, int k) {
        capacity = k;
        int resultNum = (int) Arrays.stream(operators).filter(arr -> arr[0] ==
                        2).count();
        int[] resultArray = new int[resultNum];
        for (int i = 0, j = 0; i < operators.length; i++) {
            int[] nums = operators[i];
            int operateType = nums[0];
            if (operateType == 1) {
                set(nums[1], nums[2]);
            } else {
                resultArray[j++] = get(nums[1]);
            }
        }
        return resultArray;
    }
}

编辑于 2024-04-20 22:09:08 回复(0)
GPT4:
import java.util.*;

public class Solution {
    private HashMap<Integer, Integer> keyToVal;
    private HashMap<Integer, Integer> keyToFreq;
    private HashMap<Integer, LinkedHashSet<Integer>> freqToKeys;
    private int minFreq;
    private int capacity;

    public int[] LFU(int[][] operators, int k) {
        this.capacity = k;
        this.keyToVal = new HashMap<>();
        this.keyToFreq = new HashMap<>();
        this.freqToKeys = new HashMap<>();
        this.minFreq = 0;

        ArrayList<Integer> result = new ArrayList<>();

        for (int[] op : operators) {
            if (op[0] == 1) { // set operation
                set(op[1], op[2]);
            } else if (op[0] == 2) { // get operation
                result.add(get(op[1]));
            }
        }

        return result.stream().mapToInt(i -> i).toArray();
    }

    private int get(int key) {
        if (!keyToVal.containsKey(key)) {
            return -1;
        }
        // increase the frequency of the key
        increaseFreq(key);
        return keyToVal.get(key);
    }

    private void set(int key, int value) {
        if (capacity == 0) return;

        if (keyToVal.containsKey(key)) {
            keyToVal.put(key, value);
            // increase the frequency of the key
            increaseFreq(key);
            return;
        }

        if (keyToVal.size() >= capacity) {
            removeMinFreqKey();
        }

        // add new key
        keyToVal.put(key, value);
        keyToFreq.put(key, 1);
        freqToKeys.putIfAbsent(1, new LinkedHashSet<>());
        freqToKeys.get(1).add(key);
        minFreq = 1;
    }

    private void increaseFreq(int key) {
        int freq = keyToFreq.get(key);
        keyToFreq.put(key, freq + 1);
        freqToKeys.get(freq).remove(key);
        if (freqToKeys.get(freq).isEmpty()) {
            freqToKeys.remove(freq);
            if (minFreq == freq) {
                minFreq++;
            }
        }
        freqToKeys.putIfAbsent(freq + 1, new LinkedHashSet<>());
        freqToKeys.get(freq + 1).add(key);
    }

    private void removeMinFreqKey() {
        LinkedHashSet<Integer> keyList = freqToKeys.get(minFreq);
        int oldestKey = keyList.iterator().next();
        keyList.remove(oldestKey);
        if (keyList.isEmpty()) {
            freqToKeys.remove(minFreq);
        }
        keyToVal.remove(oldestKey);
        keyToFreq.remove(oldestKey);
    }
}
Claude-3-opus:
import java.util.*;

public class Solution {
    private Map<Integer, Integer> keyToVal;
    private Map<Integer, Integer> keyToFreq;
    private Map<Integer, LinkedHashSet<Integer>> freqToKeys;
    private int minFreq;
    private int capacity;

    public int[] LFU(int[][] operators, int k) {
        keyToVal = new HashMap<>();
        keyToFreq = new HashMap<>();
        freqToKeys = new HashMap<>();
        minFreq = 0;
        capacity = k;

        List<Integer> ans = new ArrayList<>();

        for (int[] operator : operators) {
            if (operator[0] == 1) {
                set(operator[1], operator[2]);
            } else {
                ans.add(get(operator[1]));
            }
        }

        return ans.stream().mapToInt(Integer::intValue).toArray();
    }

    private int get(int key) {
        if (!keyToVal.containsKey(key)) {
            return -1;
        }

        int freq = keyToFreq.get(key);
        freqToKeys.get(freq).remove(key);

        if (freq == minFreq && freqToKeys.get(freq).isEmpty()) {
            minFreq++;
        }

        keyToFreq.put(key, freq + 1);
        freqToKeys.computeIfAbsent(freq + 1, k -> new LinkedHashSet<>()).add(key);

        return keyToVal.get(key);
    }

    private void set(int key, int value) {
        if (capacity <= 0) {
            return;
        }

        if (keyToVal.containsKey(key)) {
            keyToVal.put(key, value);
            get(key);
            return;
        }

        if (keyToVal.size() >= capacity) {
            int evictKey = freqToKeys.get(minFreq).iterator().next();
            freqToKeys.get(minFreq).remove(evictKey);
            keyToVal.remove(evictKey);
            keyToFreq.remove(evictKey);
        }

        keyToVal.put(key, value);
        keyToFreq.put(key, 1);
        freqToKeys.computeIfAbsent(1, k -> new LinkedHashSet<>()).add(key);
        minFreq = 1;
    }
}



编辑于 2024-04-15 22:52:11 回复(0)
#include <mutex>
#include <unordered_map>
#include <vector>


class Solution {
  public:
    struct Node {
        int key, val;
        Node* pre, *next;
        Node(): key(0), val(0), pre(nullptr), next(nullptr) {};
        Node(int k, int v): key(k), val(v), pre(nullptr), next(nullptr) {};
    };
    unordered_map<int, Node*> hash;
    

    void removeNode(Node* node) {
        node->pre->next = node->next;
        node->next->pre = node->pre;
    }
    void insertNode(Node* node,Node* head,Node* tail) {
        node->next=head->next;
        head->next->pre=node;
        head->next=node;
        node->pre=head;
    }

    vector<int> LFU(vector<vector<int> >& operators, int cap) {
       Node* head=new Node();
       Node* tail=new Node();
       head->next=tail;
       tail->pre=head;
       int size=0;
       vector<int>ans;
        for (int i = 0; i < operators.size(); i++) {
            int key = operators[i][1], val = operators[i][2];
            if (operators[i][0] == 1) {
                if (hash.count(key)) {
                    Node* node = hash[key];
                    node->val = val;
                    hash[key] = node;
                    removeNode(node);
                    insertNode(node,head,tail);
                }else{
                    if(cap==size){
                        hash.erase(tail->pre->key);
                        removeNode(tail->pre);
                        size--;
                    }
                    Node* node=new Node(key,val);
                    hash[key]=node;
                    insertNode(node, head, tail);
                    size++;
                }
            }
            if(operators[i][0]==2){
                if(!hash.count(key)){
                    ans.push_back(-1);
                }else{
                    Node* node=hash[key];
                    ans.push_back(node->val);
                    removeNode(node);
                    insertNode(node, head, tail);
                }
            }
        }
        return ans;
    }
};

编辑于 2024-03-28 17:28:06 回复(0)

加上最近访问会超时,不加倒数第二个用例过不去,求大佬优化一下循环,或者加一个最近访问的标记。

#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
# lfu design
# @param operators int整型二维数组 ops
# @param k int整型 the k
# @return int整型一维数组
#
class Solution:
    def LFU(self , operators: List[List[int]], k: int) -> List[int]:
        # write code here
        buf = []
        res = []
        for i in operators:
            if i[0] == 1:  # opt=1插入数据
                if i[1] in [j[0] for j in buf]:  # 如果插入数据在缓存里
                    for j in buf:
                        if j[0] == i[1]:  # 找到该数据
                            j[1] = i[2]  # 更新value
                            j[2] += 1  # 访问次数+1
                    # # 调整为最近访问
                    # for j in buf:
                    #     if j[0] == i[1]:
                    #         buf.remove(j)
                    #         buf.append(j)

                else:  # 插入数据不在缓存里
                    if len(buf) >= k:  # 已经存满
                        minfw = min([j[2] for j in buf])  # 找到访问次数最少的
                        for j in buf:
                            if j[2] == minfw:  # 更新插入数据
                                j[0] = i[1]  # 更新key
                                j[1] = i[2]  # 更新value
                                j[2] = 1  # 首次访问
                        # # 调整为最近访问
                        # for j in buf:
                        #     if j[0] == i[1]:
                        #         buf.remove(j)
                        #         buf.append(j)
                    else:  # 还没存满
                        buf.append([i[1], i[2], 1])

            else:  # opt=2访问数据
                if i[1] in [j[0] for j in buf]:  # get(x)在缓存里
                    for j in buf:
                        if j[0] == i[1]:  # 找到该数据
                            j[2] += 1  # 访问次数+1
                            res.append(j[1])
                else:
                    res.append(-1)

        return res
编辑于 2024-03-18 20:47:42 回复(0)