题目:
实现 LRUCache 类:
- LRUCache(int capacity) 以正整数作为容量 capacity 初始化 LRU 缓存
- int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
void put(int key, int value) 如果关键字已经存在,则变更其数据值;如果关键字不存在,则插入该组「key-value」。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。
进阶:你是否可以在 O(1) 时间复杂度内完成这两种操作?
思路:
如果是O(n)的时间复杂度,那么可以把数据存在slice中,每次查询或者插入时,都遍历一遍,但是要在O(1)时间复杂度内实现,必然要使用哈希表,也就是要使用空间来换时间。
在具体实现上,哈希表用于存储值,双向链表用于记录最新使用过的和最久未使用的数据,方便进行增删改查。
关键部分:
在head和tail的地方使用哨兵节点,有边界条件,可以省去判断相邻节点是否存在的情况(举个例子?)
代码实现(哈希表+双向链表):
package mainimport ("fmt")type LRUCache struct {capacity intsize intcache map[int]*DataLinkNodehead, tail *DataLinkNode}type DataLinkNode struct {key, value intnext, prev *DataLinkNode}//初始化缓存func Constructor(capacity int) *LRUCache {head := InitialNode(0, 0)tail := InitialNode(0, 0)head.next = tailtail.prev = headreturn &LRUCache{capacity: capacity,cache: make(map[int]*DataLinkNode, capacity),head: head,tail: tail,}}//初始化节点func InitialNode(key, value int) *DataLinkNode {return &DataLinkNode{key: key,value: value,}}func (l *LRUCache) Get(key int) int {if _, ok := l.cache[key]; !ok {return -1 //key不存在}node := l.cache[key]l.removeNode(node)l.moveToHead(node)return node.value}func (l *LRUCache) Put(key, value int) {if _, ok := l.cache[key]; !ok { // key不存在l.addToHead(InitialNode(key, value))l.size++if l.size > l.capacity {l.removeTail()delete(l.cache, key) //记得删除去掉的节点l.size--}} else {l.cache[key].value = valuenode := l.cache[key]l.moveToHead(node)}}//增加节点到headfunc (l *LRUCache) addToHead(node *DataLinkNode) {node.next = l.head.nextnode.prev = l.headl.head.next.prev = nodel.head.next = node}//移动节点到headfunc (l *LRUCache) moveToHead(node *DataLinkNode) {l.removeNode(node)l.addToHead(node)}//删除一个节点func (l *LRUCache) removeNode(node *DataLinkNode) {node.prev.next = node.nextnode.next.prev = node.prev}//删除最后一个节点func (l *LRUCache) removeTail() *DataLinkNode {node := l.tail.prevl.removeNode(node) //删除一个节点,直接调用自己的removeNode方法return node}func main() {cache1 := Constructor(3)cache1.Put(1, 1)cache1.Put(2, 2)cache1.Get(1)cache1.Put(3, 3)cache1.Put(4, 4)for cache1.head != nil {fmt.Println(cache1.head.key)cache1.head = cache1.head.next}}
这道题感觉还是比较麻烦,指针指来指去很容易出问题,写的时候要很细心。
补充一个数组版本的LRU实现:
type LRUCache struct {len intdataList []Data //存储key,value}type Data struct {Key intVal int}func Constructor(capacity int) LRUCache {return LRUCache{len:capacity,}}func (this *LRUCache) Get(key int) int {isExist := false //标志是否存在index := 0tmp := Data{}for i, val := range this.dataList{ //存在key,把index和value取出if val.Key == key { //同时标记isExist为trueisExist = trueindex = itmp = valbreak}}if isExist {for ; index < len(this.dataList)-1; index++ {this.dataList[index] = this.dataList[index+1]} //需要整体左移,最右边的数据是最新使用过的this.dataList[index] = tmpreturn tmp.Val}return -1}func (this *LRUCache) Put(key int, value int) {isExist := false //标志位index := 0 //索引位for i, val := range this.dataList {if val.Key == key { //如果存在key,取出index,设置isExist为trueisExist = trueindex = ibreak}}if isExist {for ; index < len(this.dataList)-1; index++ {this.dataList[index] = this.dataList[index+1]}//整体左移,最新使用过的数据放在最右边this.dataList[index] = Data{Key:key, Val:value}} else {//如果缓存已经满了,整体左移,然后把数据放在最右边一位if len(this.dataList) == this.len {for i := 0; i < this.len-1; i++ {this.dataList[i] = this.dataList[i+1]}this.dataList[this.len-1] = Data{Key:key, Val:value}} else {//如果没有满,直接插入在最后this.dataList = append(this.dataList,Data{Key:key, Val:value})}}}/*** Your LRUCache object will be instantiated and called as such:* obj := Constructor(capacity);* param_1 := obj.Get(key);* obj.Put(key,value);*/
