内容简介:运用你所掌握的数据结构,设计和实现一个获取数据写入数据
146. LRU缓存机制
运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制。它应该支持以下操作: 获取数据 get 和 写入数据 put 。
获取数据 get(key) - 如果密钥 (key) 存在于缓存中,则获取密钥的值(总是正数),否则返回 -1。
写入数据 put(key, value) - 如果密钥不存在,则写入其数据值。当缓存容量达到上限时,它应该在写入新数据之前删除最近最少使用的数据值,从而为新的数据值留出空间。
进阶:
你是否可以在 O(1) 时间复杂度内完成这两种操作?
示例:
LRUCache cache = new LRUCache( 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
解题思路
- LRU是Least Recently Used的缩写,即"最近最少使用",也就是说,LRU缓存把最近最少使用的数据移除,让给最新读取的数据
- 往往最常读取的,也是读取次数最多的
- 操作系统等最常使用的缓存策略,即LRU
- 需要在O(1)时间复杂度实现put操作,就需要使用双向链表,方便移动节点(单链表无法达到O(1))
- O(1)实现get查询操作,就需要使用map存key-node键值对,实现快速查询
- 具体详见代码注释
代码实现
// doublyLinkedNode defines a node for double-linked-list
type doublyLinkedNode struct {
prev, next *doublyLinkedNode
key, val int
}
// LRUCache defines a object for cache
type LRUCache struct {
len, cap int
first, last *doublyLinkedNode //head,tail
nodes map[int]*doublyLinkedNode //hashtable,find node in O(1)
}
// Constructor creates a cache object
func Constructor(capacity int) LRUCache {
return LRUCache{
len: 0,
cap: capacity,
first: nil,
last: nil,
nodes: make(map[int]*doublyLinkedNode, capacity),
}
}
// Get returns value by key
func (l *LRUCache) Get(key int) int {
if node, ok := l.nodes[key]; ok {
//key exist
// move the node to the head of double-linked-list
l.moveToFirst(node)
return node.val
}
//key not exist,return -1
return -1
}
// Put puts key-value pair into LRUCache
func (l *LRUCache) Put(key int, value int) {
if node, ok := l.nodes[key]; ok {
//update value of old node
node.val = value
// move the node to the head of double-linked-list
l.moveToFirst(node)
} else {
if l.len == l.cap {
delete(l.nodes, l.last.key)
l.removeLast()
} else {
l.len++
}
node := &doublyLinkedNode{
prev: nil,
next: nil,
key: key,
val: value,
}
l.nodes[key] = node
l.insertToFirst(node)
}
}
func (l *LRUCache) removeLast() {
if l.last.prev != nil {
//双向链表长度>1
l.last.prev.next = nil
} else {
//双向链表长度 == 1,first == last
l.first = nil
}
l.last = l.last.prev
}
func (l *LRUCache) moveToFirst(node *doublyLinkedNode) {
switch node {
case l.first:
return
case l.last:
l.removeLast()
default:
//在双向链中,删除 node 节点
node.prev.next = node.next
node.next.prev = node.prev
}
// 策略是
// 如果是移动node
// 先删除,再插入
l.insertToFirst(node)
}
func (l *LRUCache) insertToFirst(node *doublyLinkedNode) {
if l.last == nil {
//空的双向链表
l.last = node
} else {
node.next = l.first
l.first.prev = node
}
l.first = node
}
GitHub
- 源码在这里
- 项目中会提供各种数据结构及算法的Golang实现,以及 LeetCode 解法
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
HTTP/2基础教程
Stephen Ludin、Javier Garza / 罗正龙、郑维智 / 人民邮电出版社 / 2018-1 / 49.00元
让网站和应用更快速、更简洁、更稳健,从而有效提升用户体验,这无疑是众多开发者梦寐以求的。然而互联网发展日新月异,HTTP/1.1协议已经难以满足现今的需求。在众多Web性能提升方案中,HTTP/2值得尝试。 本书是HTTP/2实用指南,介绍了HTTP/2的设计初衷和新特性,以及如何才能充分利用这些特性来打造高性能网站及应用。作者用定量分析方法,对比了不同网络环境下及不同浏览器上HTTP/1.......一起来看看 《HTTP/2基础教程》 这本书的介绍吧!
JS 压缩/解压工具
在线压缩/解压 JS 代码
HEX CMYK 转换工具
HEX CMYK 互转工具