题目:

实现 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的地方使用哨兵节点,有边界条件,可以省去判断相邻节点是否存在的情况(举个例子?)
代码实现(哈希表+双向链表):

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. type LRUCache struct {
  6. capacity int
  7. size int
  8. cache map[int]*DataLinkNode
  9. head, tail *DataLinkNode
  10. }
  11. type DataLinkNode struct {
  12. key, value int
  13. next, prev *DataLinkNode
  14. }
  15. //初始化缓存
  16. func Constructor(capacity int) *LRUCache {
  17. head := InitialNode(0, 0)
  18. tail := InitialNode(0, 0)
  19. head.next = tail
  20. tail.prev = head
  21. return &LRUCache{
  22. capacity: capacity,
  23. cache: make(map[int]*DataLinkNode, capacity),
  24. head: head,
  25. tail: tail,
  26. }
  27. }
  28. //初始化节点
  29. func InitialNode(key, value int) *DataLinkNode {
  30. return &DataLinkNode{
  31. key: key,
  32. value: value,
  33. }
  34. }
  35. func (l *LRUCache) Get(key int) int {
  36. if _, ok := l.cache[key]; !ok {
  37. return -1 //key不存在
  38. }
  39. node := l.cache[key]
  40. l.removeNode(node)
  41. l.moveToHead(node)
  42. return node.value
  43. }
  44. func (l *LRUCache) Put(key, value int) {
  45. if _, ok := l.cache[key]; !ok { // key不存在
  46. l.addToHead(InitialNode(key, value))
  47. l.size++
  48. if l.size > l.capacity {
  49. l.removeTail()
  50. delete(l.cache, key) //记得删除去掉的节点
  51. l.size--
  52. }
  53. } else {
  54. l.cache[key].value = value
  55. node := l.cache[key]
  56. l.moveToHead(node)
  57. }
  58. }
  59. //增加节点到head
  60. func (l *LRUCache) addToHead(node *DataLinkNode) {
  61. node.next = l.head.next
  62. node.prev = l.head
  63. l.head.next.prev = node
  64. l.head.next = node
  65. }
  66. //移动节点到head
  67. func (l *LRUCache) moveToHead(node *DataLinkNode) {
  68. l.removeNode(node)
  69. l.addToHead(node)
  70. }
  71. //删除一个节点
  72. func (l *LRUCache) removeNode(node *DataLinkNode) {
  73. node.prev.next = node.next
  74. node.next.prev = node.prev
  75. }
  76. //删除最后一个节点
  77. func (l *LRUCache) removeTail() *DataLinkNode {
  78. node := l.tail.prev
  79. l.removeNode(node) //删除一个节点,直接调用自己的removeNode方法
  80. return node
  81. }
  82. func main() {
  83. cache1 := Constructor(3)
  84. cache1.Put(1, 1)
  85. cache1.Put(2, 2)
  86. cache1.Get(1)
  87. cache1.Put(3, 3)
  88. cache1.Put(4, 4)
  89. for cache1.head != nil {
  90. fmt.Println(cache1.head.key)
  91. cache1.head = cache1.head.next
  92. }
  93. }

这道题感觉还是比较麻烦,指针指来指去很容易出问题,写的时候要很细心。

补充一个数组版本的LRU实现:

  1. type LRUCache struct {
  2. len int
  3. dataList []Data //存储key,value
  4. }
  5. type Data struct {
  6. Key int
  7. Val int
  8. }
  9. func Constructor(capacity int) LRUCache {
  10. return LRUCache{
  11. len:capacity,
  12. }
  13. }
  14. func (this *LRUCache) Get(key int) int {
  15. isExist := false //标志是否存在
  16. index := 0
  17. tmp := Data{}
  18. for i, val := range this.dataList{ //存在key,把index和value取出
  19. if val.Key == key { //同时标记isExist为true
  20. isExist = true
  21. index = i
  22. tmp = val
  23. break
  24. }
  25. }
  26. if isExist {
  27. for ; index < len(this.dataList)-1; index++ {
  28. this.dataList[index] = this.dataList[index+1]
  29. } //需要整体左移,最右边的数据是最新使用过的
  30. this.dataList[index] = tmp
  31. return tmp.Val
  32. }
  33. return -1
  34. }
  35. func (this *LRUCache) Put(key int, value int) {
  36. isExist := false //标志位
  37. index := 0 //索引位
  38. for i, val := range this.dataList {
  39. if val.Key == key { //如果存在key,取出index,设置isExist为true
  40. isExist = true
  41. index = i
  42. break
  43. }
  44. }
  45. if isExist {
  46. for ; index < len(this.dataList)-1; index++ {
  47. this.dataList[index] = this.dataList[index+1]
  48. }//整体左移,最新使用过的数据放在最右边
  49. this.dataList[index] = Data{Key:key, Val:value}
  50. } else {//如果缓存已经满了,整体左移,然后把数据放在最右边一位
  51. if len(this.dataList) == this.len {
  52. for i := 0; i < this.len-1; i++ {
  53. this.dataList[i] = this.dataList[i+1]
  54. }
  55. this.dataList[this.len-1] = Data{Key:key, Val:value}
  56. } else {//如果没有满,直接插入在最后
  57. this.dataList = append(this.dataList,Data{Key:key, Val:value})
  58. }
  59. }
  60. }
  61. /**
  62. * Your LRUCache object will be instantiated and called as such:
  63. * obj := Constructor(capacity);
  64. * param_1 := obj.Get(key);
  65. * obj.Put(key,value);
  66. */