福哥答案2021-01-23:
这道题复杂度太高,短时间内很难写出来。面试的时候不建议手撕代码。
一个存节点的map+一个存桶的map+一个存桶的双向链表。桶本身也是一个双向链表。
存节点的map:key是键,value是节点。
存桶的map:key是次数,value是桶。
代码用golang编写,代码如下:

package main

import (
"container/list"
"fmt"
) func main() {
cache := Constructor(2)
cache.Put(1, 1)
cache.Put(2, 2)
cache.Get(1) // 返回 1
cache.Put(3, 3) // 去除键 2
cache.Get(2) // 返回 -1(未找到)
cache.Get(3) // 返回 3
cache.Put(4, 4) // 去除键 1
cache.Get(1) // 返回 -1(未找到)
cache.Get(3) // 返回 3
cache.Get(4) // 返回 4 } type LFUCache struct {
Cap int
Len int
//map缓存,键存key,值存kv和前后
KeyCache map[int]*list.Element //key存键,value存节点 List *list.List FreqCache map[int]*list.Element //key存次数,value存桶
} func Constructor(capacity int) LFUCache {
ret := LFUCache{}
ret.Cap = capacity
ret.KeyCache = make(map[int]*list.Element) //元素存节点
ret.FreqCache = make(map[int]*list.Element) //元素存桶
ret.List = list.New()
return ret
} func (this *LFUCache) Get(key int) int {
//已经找到当前元素了
v := this.KeyCache[key]
if v == nil {
fmt.Println(-1)
return -1
}
//移动
this.curNodeMoveToNextBucket(v) //返回当前元素的值
fmt.Println(v.Value.([]int)[1])
return v.Value.([]int)[1]
} //当前节点移动到下一个桶
func (this *LFUCache) curNodeMoveToNextBucket(v *list.Element) {
//根据当前节点的次数找到当前桶
curbucket := this.FreqCache[v.Value.([]int)[2]] //找下一桶,找不到创建新桶
nextbucket := this.FreqCache[v.Value.([]int)[2]+1]
if nextbucket == nil {
nextbucket = this.List.InsertAfter(list.New(), curbucket)
this.FreqCache[v.Value.([]int)[2]+1] = nextbucket
} //把当前节点放在下一桶里
//nextbucket.Value.(*list.List).PushBack(v.Value),这样的代码,leetcode不能通过。原因是元素移动后,已经不是以前的元素了。所以map需要重新赋值。这个错误,我花了1个小时才找到,请谨慎。
this.KeyCache[v.Value.([]int)[0]] = nextbucket.Value.(*list.List).PushBack(v.Value) //当前桶删除当前节点
curbucket.Value.(*list.List).Remove(v) //如果当前桶为空,直接删除当前桶。
if curbucket.Value.(*list.List).Len() == 0 {
this.List.Remove(curbucket)
delete(this.FreqCache, v.Value.([]int)[2])
} //当前节点次数加1
v.Value.([]int)[2]++
} func (this *LFUCache) Put(key int, value int) {
if this.Cap == 0 {
return
}
if v, ok := this.KeyCache[key]; ok { //缓存里有
//修改值
v.Value.([]int)[1] = value //移动
this.curNodeMoveToNextBucket(v)
} else { //缓存里没有
if this.Len == this.Cap {
//获取可能需要删除的桶
deleteBucket := this.List.Front() //获取需要删除的元素
deleteE := deleteBucket.Value.(*list.List).Front() //删除元素
delete(this.KeyCache, deleteE.Value.([]int)[0])
deleteBucket.Value.(*list.List).Remove(deleteE) //可能需要删除的桶如果没有元素,删除桶。并且需要删除的元素的次数不是1
if deleteBucket.Value.(*list.List).Len() == 0 {
this.List.Remove(deleteBucket)
delete(this.FreqCache, deleteE.Value.([]int)[2])
}
} else {
this.Len++
} //获取次数为1的桶
oneTimeBucket := this.FreqCache[1] //获取不到就创建桶
if oneTimeBucket == nil {
oneTimeBucket = this.List.PushFront(list.New())
this.FreqCache[1] = oneTimeBucket
} this.KeyCache[key] = oneTimeBucket.Value.(*list.List).PushBack([]int{key, value, 1}) }
}

  执行结果如下:

2021-01-23:LFU手撸,说下时间复杂度和空间复杂度。的更多相关文章

  1. 手撸一个SpringBoot-Starter

    1. 简介 通过了解SpringBoot的原理后,我们可以手撸一个spring-boot-starter来加深理解. 1.1 什么是starter spring官网解释 starters是一组方便的依 ...

  2. 【分布式锁的演化】终章!手撸ZK分布式锁!

    前言 这应该是分布式锁演化的最后一个章节了,相信很多小伙伴们看完这个章节之后在应对高并发的情况下,如何保证线程安全心里肯定也会有谱了.在实际的项目中也可以参考一下老猫的github上的例子,当然代码没 ...

  3. 手撸一个springsecurity,了解一下security原理

    手撸一个springsecurity,了解一下security原理 转载自:www.javaman.cn 手撸一个springsecurity,了解一下security原理 今天手撸一个简易版本的sp ...

  4. php手撸轻量级开发(一)

    聊聊本文内容 之前讲过php简单的内容,但是原生永远是不够看的,这次用框架做一些功能性的事情. 但是公司用自己的框架不能拿出来,用了用一些流行的框架比如tp,larveral之类的感觉太重,CI也不顺 ...

  5. 使用Java Socket手撸一个http服务器

    原文连接:使用Java Socket手撸一个http服务器 作为一个java后端,提供http服务可以说是基本技能之一了,但是你真的了解http协议么?你知道知道如何手撸一个http服务器么?tomc ...

  6. 康少带你手撸orm

    orm 什么是orm? 对象关系映射: 一个类映射成一张数据库的表 类的对象映射成数据库中的一条条数据 对象点数据映射成数据库某条记录的某个值 优点:不会写sql语句的程序员也可以很6的操作sql语句 ...

  7. .NET手撸2048小游戏

    .NET手撸2048小游戏 2048是一款益智小游戏,得益于其规则简单,又和2的倍数有关,因此广为人知,特别是广受程序员的喜爱. 本文将再次使用我自制的"准游戏引擎"FlysEng ...

  8. .NET手撸绘制TypeScript类图——下篇

    .NET手撸绘制TypeScript类图--下篇 在上篇的文章中,我们介绍了如何使用.NET解析TypeScript,这篇将介绍如何使用代码将类图渲染出来. 注:以防有人错过了,上篇链接如下:http ...

  9. 纯手撸web框架

    纯手撸web框架 一.Web应用的组成 接下来我们学习的目的是为了开发一个Web应用程序,而Web应用程序是基于B/S架构的,其中B指的是浏览器,负责向S端发送请求信息,而S端会根据接收到的请求信息返 ...

  10. 99%的程序员都在用Lombok,原理竟然这么简单?我也手撸了一个!|建议收藏!!!

    罗曼罗兰说过:世界上只有一种英雄主义,就是看清生活的真相之后依然热爱生活. 对于 Lombok 我相信大部分人都不陌生,但对于它的实现原理以及缺点却鲜为人知,而本文将会从 Lombok 的原理出发,手 ...

随机推荐

  1. ACM 的正确入门方式是什么?

    作者:数学lover 链接:https://www.zhihu.com/question/51727516/answer/127265733 来源:知乎 著作权归作者所有.商业转载请联系作者获得授权, ...

  2. 修改/编辑jar包

    替换或者导入jar包时,jar包被自动压缩,springboot规定嵌套的jar包不能在被压缩的情况下存储. 解决(本文以升级ojdbc包为例): 使用jar命令解压jar包,在压缩包外重新替换jar ...

  3. SQL统计(一)

    参考博客: https://blog.csdn.net/GuTiDong/article/details/81326787 按月份统计每个月的订单总金额 https://blog.csdn.net/h ...

  4. CF1141 Div3 欢乐信心赛

    非常轻松的比赛,连我这样的菜鸡也感到充满力量. A 用类似于质因数分解的操作搞一搞即可. B 将环复制一遍. C 可以发现 \(q\) 就是差分数组.那么差分数组之和最大的地方就是原序列的最大值,为 ...

  5. nginx的location与proxy_pass配置超详细讲解及其有无斜杠( / )结尾的区别

    本文所使用的环境信息如下: windows11 (主机系统) virtual-box-7.0环境下的ubuntu-18.04 nginx-1.22.1 (linux) 斜杠结尾之争 实践中,nginx ...

  6. Kafka 之 HW 与 LEO

    更多内容,前往 IT-BLOG HW(High Watermark):俗称高水位,它标识了一个特定的消息偏移量(offset),消费者只能拉取到这个 offset 之前的消息.分区 ISR 集合中的每 ...

  7. 解决ueditor表格拖拽没反应的问题

    背景 ueditor作为百度推出的富文本编辑框,以功能强大著称. 笔者最近用这个编辑框做了一个自定义打印格式的功能.允许用户在富文本编辑框中设定打印格式,再实际打印时,根据关键字替换数据库中信息,然后 ...

  8. jquery中判断复选框有没有被选上

    页面部分: <input type="checkbox" id="cbx" /><label for="cbx">点 ...

  9. Git链接上游仓库

    技术背景 在Git的操作过程中,一般的组织内部工作模式可以在同一个仓库上的master-develop-feature不同分支上进行开发,也有一些人和外部协作者会通过Fork到自己本地的仓库进行更新的 ...

  10. R语言网络数据爬虫之三个问题

    现在大家对爬虫的兴趣不断高涨,R和PYTHON是两个非常有力的爬虫工具.Python倾向于做大型爬虫,与R相比,语法相对复杂,因此Python爬虫的学习曲线会相对陡峭.对于那些时间宝贵,又想从网上获取 ...