package main
import (
"time"
"container/heap"
)
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
* lfu design
* @param operators int整型二维数组 ops
* @param k int整型 the k
* @return int整型一维数组
*/
type entry struct {
key int
val int
updatedAt time.Time
}
type LfuEntry struct {
entry entry
count int
index int
}
type mypriority []*LfuEntry
func (p mypriority) Len() int {
return len(p)
}
func (p mypriority) Swap(i, j int) {
p[i], p[j] = p[j], p[i]
p[i].index = i
p[j].index = j
}
func (p mypriority) Less(i, j int) bool {
if p[i].count == p[j].count {
return p[i].entry.updatedAt.Before(p[j].entry.updatedAt)
}
return p[i].count < p[j].count
}
func (p *mypriority) Push(x interface{}) {
lfuEntry := x.(*LfuEntry)
lfuEntry.index = p.Len()
(*p) = append((*p), lfuEntry)
}
func (p *mypriority) Pop() interface{} {
oldp := *p
n := len(oldp)
entry := oldp[n-1]
oldp[n-1] = nil
newp := oldp[:n-1]
// 1 2 3 4 5 -> 2 3 4 5(索引 1 2 3 4) 更新为(0 1 2 3)
for i := 0; i < len(newp); i++ {
newp[i].index = i
}
*p = newp
return entry
}
type LFUCache struct {
maxCacheSize int
nSize int
m map[int]*LfuEntry
priority *mypriority
}
func NewLFUCache(cachesize int) LFUCache {
priority := make(mypriority, 0)
return LFUCache{
maxCacheSize: cachesize,
m: make(map[int]*LfuEntry),
priority: &priority,
}
}
func NewLFUEntry(key, val int) *LfuEntry {
return &LfuEntry{
entry: entry{
key: key,
val: val,
updatedAt: time.Now(),
},
}
}
func (l *LFUCache) Get(key int) int {
if lfuEntry, ok := l.m[key]; ok {
lfuEntry.touch()
heap.Fix(l.priority, lfuEntry.index)
return lfuEntry.entry.val
}
return -1
}
func (l *LFUCache) Put(key, val int) {
if lfuEntry, ok := l.m[key]; ok {
lfuEntry.touch()
// index 节点 count 发生变化,调整堆
heap.Fix(l.priority, lfuEntry.index)
lfuEntry.entry.val = val
} else {
newLfuEntry := NewLFUEntry(key, val)
newLfuEntry.touch()
if l.nSize == l.maxCacheSize {
l.Remove()
}
l.nSize++
l.m[key] = newLfuEntry
heap.Push(l.priority, newLfuEntry)
}
}
func (l *LFUCache) Remove() {
lfuEntry := heap.Pop(l.priority).(*LfuEntry)
delete(l.m, lfuEntry.entry.key)
l.nSize--
}
func (l *LfuEntry) touch() {
l.count++
l.entry.updatedAt = time.Now()
}
func LFU( operators [][]int , k int ) []int {
// write code here
lfu, ans := NewLFUCache(k), []int{}
for _, operator := range operators {
if operator[0] == 1 {
lfu.Put(operator[1], operator[2])
} else {
ans = append(ans, lfu.Get(operator[1]))
}
}
return ans
}