用go语言实现LFU缓存,两种方法实现_leetcode
2018-11-09 本文已影响0人
fjxCode
LFU Cache用go语言实现LFU缓存,两种方法实现
题目:
Design and implement a data structure for Least Frequently Used (LFU) cache. It should support the following operations: get and put.
get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.
put(key, value) - Set or insert the value if the key is not already present. When the cache reaches its capacity, it should invalidate the least frequently used item before inserting a new item. For the purpose of this problem, when there is a tie (i.e., two or more keys that have the same frequency), the least recently used key would be evicted.
Follow up:
Could you do both operations in O(1) time complexity?
Example:
LFUCache cache = new LFUCache( 2 /* capacity */ );
cache.put(1, 1);
cache.put(2, 2);
cache.get(1); // returns 1
cache.put(3, 3); // evicts key 2
cache.get(2); // returns -1 (not found)
cache.get(3); // returns 3.
cache.put(4, 4); // evicts key 1.
cache.get(1); // returns -1 (not found)
cache.get(3); // returns 3
cache.get(4); // returns 4
思路:
- 双哈希实现,mapKvc存K-[V,Cnt]。mapFreq记录Cnt-[同频率节点]。min记录最小频率的一组,容量超限时,从这里清元素。
- Get方法:更新mapKvs中的Cnt,mapFreq更新所在的频率组。mapFreq[min]组为空要处理下。
- Put方法:存在key,则加入mapKvs,并用get()方法touch一次。不存在key,如果超容量先从mapFreq[min]清一个元素,加到mapKvs,mapFreq,更新min=1。
- 细节:同步率的一组,可以用切片、链表。而用哈希效率更高些。代价是容量超限时,删除一个元素的代码长一些。
错解:(未满足题意的一个要求)
//仅能通过18/23个用例。
type LfuVc struct {
value int
count int
}
type LFUCache struct {
mapKvs map[int]LfuVc
mapFreq map[int]map[int]int
min int
cap int
}
func Constructor(capacity int) LFUCache {
return LFUCache{
mapKvs: make(map[int]LfuVc, capacity),
mapFreq: make(map[int]map[int]int, capacity),
min: 0,
cap: capacity,
}
}
func (this *LFUCache) Get(key int) int {
lfuVcElem, ok := this.mapKvs[key]
if !ok {
return -1
}
this.mapKvs[key] = LfuVc{value: lfuVcElem.value, count: lfuVcElem.count + 1}
cnt := lfuVcElem.count
delete(this.mapFreq[cnt], key)
_, ok = this.mapFreq[cnt+1]
if !ok {
this.mapFreq[cnt+1] = make(map[int]int, this.cap)
}
this.mapFreq[cnt+1][key] = 1
//update min
if cnt == this.min && len(this.mapFreq[cnt])==0{
this.min++//由于被查的key的count由min升级到min+1,所以min+1必然非空
}
return lfuVcElem.value
}
func (this *LFUCache) Put(key int, value int) {
if this.cap == 0 {
return
}
_, ok := this.mapKvs[key]
if ok {
this.mapKvs[key] = LfuVc{value:value,count:this.mapKvs[key].count}//更新count留给this.Get()做
this.Get(key)
return
}
if len(this.mapKvs) >= this.cap {
//if this.min>1{
// //满容,且都是高频元素,不执行Put
// return
//}
var minOneKey int
for key,_ := range this.mapFreq[this.min]{
minOneKey = key
break
}
delete(this.mapKvs,minOneKey)
delete(this.mapFreq[this.min],minOneKey)
}
this.mapKvs[key] = LfuVc{value: value, count: 1}
if this.min != 1 {
this.mapFreq[1] = make(map[int]int, this.cap)
}
this.mapFreq[1][key] = 1
this.min = 1
}
问题分析:
- 补充一个题目的要求,when there is a tie (i.e., two or more keys that have the same frequency), the least recently used key would be evicted.
- 所以虽然用Set存同频率KV的查找效率高,但无奈不符合题意,改用链表写。
- 若是随机删除一个同频元素,就任选一个算法了。
正确解:
package main
import (
"container/list"
"fmt"
)
func main() {
c := Constructor(2)
c.Put(2, 1)
c.Put(1, 1)
fmt.Println(c.Get(2))
c.Put(4, 1)
fmt.Println(c.Get(1))
fmt.Println(c.Get(2))
}
type LfuVc struct {
value int
count int
}
type LFUCache struct {
mapKvs map[int]LfuVc
mapFreq map[int]*list.List
min int
cap int
}
func Constructor(capacity int) LFUCache {
return LFUCache{
mapKvs: make(map[int]LfuVc, capacity),
mapFreq: make(map[int]*list.List, capacity),
min: 0,
cap: capacity,
}
}
func (this *LFUCache) Get(key int) int {
lfuVcElem, ok := this.mapKvs[key]
if !ok {
return -1
}
this.mapKvs[key] = LfuVc{value: lfuVcElem.value, count: lfuVcElem.count + 1}
cnt := lfuVcElem.count
for e := this.mapFreq[cnt].Front();e!=nil;e = e.Next(){
if e.Value.(int) == key{
this.mapFreq[cnt].Remove(e)
break
}
}
if this.mapFreq[cnt+1] == nil{
this.mapFreq[cnt+1] = list.New()
}
this.mapFreq[cnt+1].PushBack(key)
//update min
if cnt == this.min && this.mapFreq[cnt].Len()==0{
this.min++//由于被查的key的count由min升级到min+1,所以min+1必然非空
}
return lfuVcElem.value
}
func (this *LFUCache) Put(key int, value int) {
if this.cap == 0 {
return
}
_, ok := this.mapKvs[key]
if ok {
this.mapKvs[key] = LfuVc{value:value,count:this.mapKvs[key].count}//更新count留给this.Get()做
this.Get(key)
return
}
if len(this.mapKvs) >= this.cap {
//if this.min > 1 {
// //满容,且都是高频元素,不执行Put
// return
//}
l := this.mapFreq[this.min]
delete(this.mapKvs, l.Front().Value.(int))
l.Remove(l.Front())
}
this.mapKvs[key] = LfuVc{value: value, count: 1}
if this.min != 1 {
this.mapFreq[1] = list.New()
}
this.mapFreq[1].PushBack(key)
this.min = 1
}