首页 > 试题广场 >

设计LFU缓存结构

[编程题]设计LFU缓存结构
  • 热度指数:23499 时间限制: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   

备注:

双哈希表

func LFU(operators [][]int, k int) []int {
    lfuCache, ans := NewLFUCache(k), []int{}
    for _, item := range operators {
        switch item[0] {
        case 1:
            lfuCache.Set(item[1], item[2])
        case 2:
            ans = append(ans, lfuCache.Get(item[1]))
        }
    }
    return ans
}

type LFUNode struct {
    key   int
    value int
    times int
    prev  *LFUNode
    next  *LFUNode
}

type LFUCache struct {
    mapOne   map[int]*LFUNode
    mapTwo   map[int][2]*LFUNode
    cap      int
    len      int
    minTimes int
}

func NewLFUCache(capacity int) *LFUCache {
    return &LFUCache{
        mapOne:   map[int]*LFUNode{},
        mapTwo:   map[int][2]*LFUNode{},
        cap:      capacity,
        len:      0,
        minTimes: -1,
    }
}

func (lfu *LFUCache) Get(key int) int {
    node, ok := lfu.mapOne[key]
    if !ok {
        return -1
    }
    lfu.delete(node)
    node.times++
    lfu.insert(node)

    return node.value
}

func (lfu *LFUCache) Set(key, value int) {
    if node, ok := lfu.mapOne[key]; ok {
        lfu.delete(node)
        node.value = value
        node.times++
        lfu.insert(node)
    } else {
        if lfu.len == lfu.cap {
            headTail := lfu.mapTwo[lfu.minTimes]
            delete(lfu.mapOne, headTail[1].prev.key)
            lfu.delete(headTail[1].prev)
            lfu.len--
        }
        node := &LFUNode{key: key, value: value, times: 1}
        lfu.mapOne[key] = node
        lfu.insert(node)
        lfu.minTimes = 1
        lfu.len++
    }
}

func (lfu *LFUCache) delete(node *LFUNode) {
    headTail := lfu.mapTwo[node.times]
    if node.prev == headTail[0] && node.next == headTail[1] && node.times == lfu.minTimes {
        lfu.minTimes++
    }
    node.prev.next, node.next.prev = node.next, node.prev
}

func (lfu *LFUCache) insert(node *LFUNode) {
    if headTail, ok := lfu.mapTwo[node.times]; ok {
        head := headTail[0]
        head.next, node.prev, node.next, head.next.prev = node, head, head.next, node
    } else {
        head, tail := &LFUNode{}, &LFUNode{}
        head.next, tail.prev = tail, head
        lfu.mapTwo[node.times] = [2]*LFUNode{head, tail}
        head.next, node.prev, node.next, head.next.prev = node, head, head.next, node
    }
}
编辑于 2024-01-31 02:32:20 回复(0)
package main

/**
 * lfu design
 * @param operators int整型二维数组 ops
 * @param k int整型 the k
 * @return int整型一维数组
*/
func LFU( operators [][]int ,  k int ) []int {
    // 参考:https://blog.csdn.net/helen920318/article/details/105324533
    result := make([]int, 0)
    s := Constructor(k)
    for _, v := range operators {
        if v[0] == 1 {
            s.Put(v[1], v[2])
        } else { //v[0] ==2
            result = append(result, s.Get(v[1]))
        }
    }
    return result
}

type LFUCache struct {
    cache map[int]*Node
    freq map[int]*DoubleList
    ncap,si***Freq int
}


func Constructor(capacity int) LFUCache {
    return LFUCache{
        cache:make(map[int]*Node),
        freq:make(map[int]*DoubleList),
        ncap:capacity,
    }
}


func (this *LFUCache) Get(key int) int {
    if node,ok := this.cache[key];ok {
        this.IncFreq(node)
        return node.val
    }
    return -1
}


func (this *LFUCache) Put(key int, value int)  {
    if this.ncap==0 {
        return
    }
    if node,ok := this.cache[key];ok {
        node.val = value
        this.IncFreq(node)
    } else {
        if this.size>=this.ncap {
            node := this.freq[this.minFreq].RemoveLast()
            delete(this.cache,node.key)
            this.size--
        }
        x := &Node{key:key,val:value,freq:1}
        this.cache[key] = x
        if this.freq[1] == nil {
            this.freq[1] = CreateDL()
        }
        this.freq[1].AddFirst(x)
        this.minFreq = 1
        this.size++
    }
}
//结点的频次增加
func (this *LFUCache) IncFreq(node *Node) {
    _freq := node.freq
    this.freq[_freq].Remove(node)
    if this.minFreq==_freq&&this.freq[_freq].IsEmpty() {
        this.minFreq++
        delete(this.freq,_freq)
    }

    node.freq++
    if this.freq[node.freq]==nil {
        this.freq[node.freq]=CreateDL()
    }
    this.freq[node.freq].AddFirst(node)
}
type DoubleList struct {
    head,tail *Node
}
type Node struct {
    prev,next *Node
    key,val,freq int
}
//新建双向链表
func CreateDL() *DoubleList {
    head,tail := &Node{},&Node{}
    head.next,tail.prev = tail,head
    return &DoubleList {
        head:head,
        tail:tail,
    }
}
func (this *DoubleList) AddFirst(node *Node) {
    node.next = this.head.next
    node.prev = this.head

    this.head.next.prev = node
    this.head.next = node
}

func (this *DoubleList) Remove (node *Node) {
    node.prev.next = node.next
    node.next.prev = node.prev

    node.next = nil
    node.prev = nil
}

func (this *DoubleList) RemoveLast() *Node {
    if this.IsEmpty() {
        return nil
    }

    last := this.tail.prev
    this.Remove(last)
    return last
}
func (this *DoubleList) IsEmpty() bool {
    return this.head.next==this.tail
}


发表于 2022-05-22 12:27:14 回复(0)

问题信息

难度:
2条回答 3730浏览

热门推荐

通过挑战的用户

查看代码