福哥答案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. nginx 代理路径

    反向代理被代理url没有截取 /report/api/ /report/api/bussinessRisk/zhucai/creditInquiry 应该是/bussinessRisk/zhucai/ ...

  2. 【BUUCTF]ACTF2020 新生赛Exec1write up

    根据题目分析,俺们要用ping命令! 打开靶机,输入127.0.0.1尝试提交,直接出现无过滤: 尝试管道符执行命令,常见管道符: 1.|(就是按位或),直接执行|后面的语句 2.||(就是逻辑或), ...

  3. Linux系统mysql免安装版配置指南

    1.下载(/usr/local目录) wget https://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-5.7.32-linux-glibc2.12-x ...

  4. 4.错误代码C1083

    有的时候在VS中遇到的error C1083: 无法打开**: " * .*": No such file or directory的错误,这里总结了我遇到过的情况: 错误 C10 ...

  5. ctfshow VIP限免题目(最新)

    源码泄露 这一题主要考察如何查看网页源代码,查看方式主要有三种 在网页前面加上view-source: 右键页面,点击查看页面源代码 键盘上按下F12打开开发者工具,在查看器中查看源代码 这一题随便一 ...

  6. redis.clients.jedis.exceptions.JedisConnectionException: Failed connecting to "xxxxx"

    Java 连接 Redis所遇问题 1. 检查Linux是否关闭防火墙,或对外开放redis默认端口6379 关闭防火墙. systemctl stop firewalld 对外开放端口.firewa ...

  7. CSAPP-Architecture Lab

    Part A 前置准备 gcc -Wall -O1 -g -c yis.c gcc -Wall -O1 -g -c isa.c gcc -Wall -O1 -g yis.o isa.o -o yis ...

  8. 用Python基于Google Bard做一个交互式的聊天机器人

    用Python基于Google Bard做一个交互式的聊天机器人 之前已经通过浏览器试过了 Google Bard ,更多细节请看: Try out Google Bard, Will Google ...

  9. DevOps 在未来将如何演进?丨行业观察

    自2007年 DevOps 这一概念推出以来,越来越多企业开始将开发和运维团队结合在一起,以加快部署速度,提高软件开发生命周期的效率和协作.但是,诸多因素都会对 DevOps 是否成功产生影响,例如组 ...

  10. php in_array 遍历,in_array大数组查询性能问题

    问题最近在实现一个项目接口的时候发现当数组过大的时候,数据返回的速度有点慢.接口数据返回最长反应时间2s,经过反复调试发现代码段耗时最长的部分在in_array()函数.解决过程在stackoverf ...