Design and implement an LRU cache class



Implement lrucache class:

  • Lrucache (int capacity) initializes the LRU cache with a positive integer as capacity
  • Int get (int key) if the keyword key exists in the cache, the value of the keyword is returned; otherwise, – 1 is returned.
  • Void put (int key, int value) if the keyword already exists, change its data value; If the keyword does not exist, insert the group “key value”. When the cache capacity reaches the maximum, it should delete the longest unused data value before writing new data, so as to make room for new data values.

Advanced: can you complete these two operations within o (1) time complexity?


If the time complexity is O (n), you can store the data in slice and traverse it every time you query or insert. However, to implement it within o (1) time complexity, you must use hash table, that is, use space for time.

In the specific implementation, the hash table is used to store values, and the two-way linked list is used to record the latest and longest unused data, which is convenient for addition, deletion, modification and query.

Key parts:

Using sentinel nodes in head and tail has boundary conditions, which can eliminate the need to judge whether adjacent nodes exist (for example?)

Code implementation (Hash Table + bidirectional linked list):

Package mainimport ("FMT") type lrucache struct {capacity int size int cache map [int] * datalinknode head, tail * datalinknode} type datalinknode struct {key, value int next, prev * datalinknode} // initialize cache func constructor (capacity int) * lrucache {head: = initialnode (0, 0) tail: = initialnode (0, 0) = tail tail.prev = head return & lrucache {capacity: capacity, cache: make (map [int] * datalinknode, capacity), head: head, tail: tail,} // initialize node func initialnode (key, value, int) * datalinknode {return & datalinknode {key: key, value,}} func (L * lrucache) Get (key int) int {if, OK: = l.cache [key];! OK {return - 1 // key does not exist} 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 does not exist l.addtohead (initialnode (key, value)) l. Size + + if l.size > l.capacity {l.removetail() delete (l.cache, key) // remember to delete the removed node l.size --}} else {l.cache [key]. Value = value node: = l.cache [key] l.movetohead (node)} // add the node to headfunc (L * lrucache) addtohead (node * datalinknode) { = node.prev = L.Head = node = node} // move the node to headfunc (L * lrucache) movetohead (node * datalinknode) {l.removenode (node) l.addtohead (node)} // delete a node func (L * lrucache) removenode (node * datalinknode) { = node.prev = node. Prev} //Delete the last node func (L * lrucache) removetail() * datalinknode {node: = l.tail.prev l.removinode (node) // delete a node and directly call its own removinode method 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 =    }}

This problem is still troublesome. It’s easy to have problems pointing around. You should be very careful when writing.

Add an array version of LRU implementation:

Type lrucache struct {len int datalist [] data // store key, value} type data struct {key int Val int} func constructor (capacity int) lrucache {return lrucache {len: capacity,}} func (this * lrucache) get (key int) int {isexist: = false // whether the flag exists index: = 0 TMP: = data {} For I, Val: = range this. Datalist {// there is a key. Take out the index and value if val.key = = key {// mark isexist as true isexist = true index = I TMP = Val break}} if isexist {for; index < len (this. Datalist) - 1; index + + {this. Datalist [index] =This. Datalist [index + 1]} // it needs to move left as a whole. The data on the far right is the latest used this. Datalist [index] = TMP return TMP. Val} return - 1}func (this * lrucache) put (key int, value int) {isexist: = false // flag bit index: = 0 // index bit for I, Val: = range this. Datalist {if val.key = = key {// if a key exists, take out the index and set isexist to true isexist = true index = I break}} if isexist {for; index < len (this. Datalist) - 1; index + + {this. Datalist [index] = this. Datalist [index + 1]} // move the whole to the left, and put the latest used data on the rightmost this. Datalist [index] = data {key: key, Val: value}} else {// if the cache is full, move the whole to the left, and then put the data in the rightmost bit 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 {// if it is not full, insert it directly at the end. This. Datalist = append (this. Datalist, data {key: key, Val: value})}} / * * * your lrucache object will be installed and called as such: * obj: = constructor (capacity); * param_1: = obj. Get (key); * obj. Put (key, value)*/

Recommended Today

Windows terminal uses nushell+oh-my-posh to beautify

First look at the renderings Please point out if the steps are wrong. Install nushell from github Download from github releaseRelease 0.66.2 · nushell/nushell ( github release download speed may be slow, you can download it hereDownload ( Install windows terminal in microsoft store Install oh-my-posh on Microsoft Store Winget can also be used, but […]