2020-09-18:LRU手撸,说下时间复杂度和空间复杂度。
时间:2022-07-25
本文章向大家介绍2020-09-18:LRU手撸,说下时间复杂度和空间复杂度。,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
福哥答案2020-09-18:
方法:哈希表 + 双向链表。
时间复杂度:对于 put 和 get 都是 O(1)。
空间复杂度:O(capacity),因为哈希表和双向链表最多存储 capacity+1 个元素。
代码用go语言编写,代码如下:
package test40_lru
import (
"fmt"
"testing"
)
/*
哈希表 + 双向链表
时间复杂度:对于 put 和 get 都是 O(1)O(1)。
空间复杂度:O(capacity),因为哈希表和双向链表最多存储 capacity+1 个元素。
*/
//https://leetcode-cn.com/problems/lru-cache/solution/lruhuan-cun-ji-zhi-by-leetcode-solution/
//go test -v -test.run TestLru
func TestLru(t *testing.T) {
cache := NewLRUCache(2)
cache.Put(1, 1)
cache.Put(2, 2)
cache.Get(1) // 返回 1
cache.Put(3, 3) // 该操作会使得关键字 2 作废
cache.Get(2) // 返回 -1 (未找到)
cache.Put(4, 4) // 该操作会使得关键字 1 作废
cache.Get(1) // 返回 -1 (未找到)
cache.Get(3) // 返回 3
cache.Get(4) // 返回 4
}
type LRUCache struct {
size int
capacity int
cache map[int]*DLinkedNode
head, tail *DLinkedNode
}
type DLinkedNode struct {
key, value int
prev, next *DLinkedNode
}
func NewDLinkedNode(key, value int) *DLinkedNode {
return &DLinkedNode{
key: key,
value: value,
}
}
func NewLRUCache(capacity int) LRUCache {
l := LRUCache{
cache: map[int]*DLinkedNode{},
head: NewDLinkedNode(0, 0),
tail: NewDLinkedNode(0, 0),
capacity: capacity,
}
l.head.next = l.tail
l.tail.prev = l.head
return l
}
//获取元素
func (f *LRUCache) Get(key int) int {
//如果缓存里未找到元素
if _, ok := f.cache[key]; !ok {
fmt.Println(-1)
return -1
}
//缓存里有元素
node := f.cache[key]
//如果 key 存在,先通过哈希表定位,再移到头部
f.moveToHead(node)
fmt.Println(node.value)
return node.value
}
//放入元素
func (f *LRUCache) Put(key int, value int) {
//如果缓存里没有元素
if _, ok := f.cache[key]; !ok {
node := NewDLinkedNode(key, value)
f.cache[key] = node
//放在头部
f.addToHead(node)
f.size++
//如果元素个数大于容量,需要删除元素
if f.size > f.capacity {
//删除链表尾部
removed := f.removeTail()
//删除map中的key
delete(f.cache, removed.key)
f.size--
}
} else { //缓存里有元素
//获取元素
node := f.cache[key]
//修改值
node.value = value
//移动到链表头
f.moveToHead(node)
}
}
//添加到头节点
func (f *LRUCache) addToHead(node *DLinkedNode) {
node.prev = f.head
node.next = f.head.next
f.head.next.prev = node
f.head.next = node
}
//删除节点
func (f *LRUCache) removeNode(node *DLinkedNode) {
node.prev.next = node.next
node.next.prev = node.prev
}
//移动到头节点
func (f *LRUCache) moveToHead(node *DLinkedNode) {
f.removeNode(node)
f.addToHead(node)
}
//删除尾部
func (f *LRUCache) removeTail() *DLinkedNode {
node := f.tail.prev
f.removeNode(node)
return node
}
执行结果如下:
***
[评论](https://user.qzone.qq.com/3182319461/blog/1600382890)
- vue-cli生成的项目配置开发和生产环境不同的接口
- 【52ABP实战教程】0.1-- Devops如何用VSTS持续集成到Github仓库!
- 学习zepto.js(对象方法)[4]
- 事件绑定的几种常见方式
- vue的iview列表table render函数设置DOM属性值的方法
- js焦点轮播图
- vue父组件中获取子组件中的数据
- 学习zepto.js(对象方法)[3]
- bootstrap 标签页tab切换js(含报错原因)
- 学习zepto.js(对象方法)[2]
- vue-router 2 跳转失败原因
- 学习zepto.js(对象方法)[1]
- html5简单拖拽实现自动左右贴边+幸运大转盘
- 欧拉筛素数
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- helm——工具使用举例
- Helm工具安装配置——2.14.3
- 论程序的健壮性——就看Redis
- SAP Spartacus路由参数的默认配置
- 这次用近万字的讲解带你干掉堆!
- Postgresql PL/PGSQL 程序语言系列 1 (存储过程过时了吗,与函数)
- Postgresql 从那个点看要优于 ORACLE SQL SERVER MYSQL
- VBA解析VBAProject 04——run length encoding
- TRTC Android端开发接入学习之实现语音聊天室(九)
- VBA解析VBAProject 03——解析dir流
- VBA解析VBAProject 01——实现的功能
- VBA解析VBAProject 02——解析
- 光怪陆离的世界之Delaunay三角剖分和Voronoi图
- Angular里的routerLink不能按照期望工作的一个问题
- 哈希算法在判定树同构方面的应用(上)