1
+ """
2
+ I learned this answer from @tusizi; rewrote it.
3
+
4
+ Let's analyze the problem
5
+ If we need get() to be O(1),
6
+ we must definitely use a hashmap(dictionary) to store the key value.
7
+
8
+ put() is not a problem, since we are only setting value.
9
+ The problem is when we excceed the capacity.
10
+ How do we find the least-used key and remove it from the hashmap?
11
+ We need something for us to sort from most-frequent-used to least-used.
12
+
13
+ So what else common data structure do we know?
14
+ Array? no, we will need to iterate to the whole array to find what we need. and it is not easy to add or remove.
15
+ Tree? not likely.
16
+ Min-heap? even though we can get the least-used, but it need O(LogN) to set the most-frequent-used.
17
+ Link list? Bingo!
18
+
19
+ We also need it to be a double link list, so we can remove the tail.
20
+ We also need the node to store the key when we remove the tail, we can also remove it in the hashmap
21
+ We also need the node to store the val when we get().
22
+
23
+ It would be like:
24
+ head<->node1<->node2<->node3 ... nodeN<->tail
25
+ (most-frequent-used to least-used)
26
+
27
+ So the main idea now is to use hashmap to store the key:Node pair [0]
28
+ If we put or get any key-value pair, we move its node to the front of the line (I call this promote()) [1]
29
+ The front of the line means we put it just after head.
30
+ If we excced the capacity, we remove the node at the end of the line [2]
31
+ The end of the line means the node just before tail.
32
+
33
+ The head and tail is just a dummy, [3]
34
+ for us to keep track of the first and the last of the linklist
35
+ and don't have worry about the edge case.
36
+ """
37
+ class Node (object ):
38
+ def __init__ (self , key , val ):
39
+ self .key = key
40
+ self .val = val
41
+ self .next = None
42
+ self .prev = None
43
+
44
+ class LRUCache (object ):
45
+ def __init__ (self , capacity ):
46
+ self .capacity = capacity
47
+ self .dic = {} #[0]
48
+ self .head = Node (0 , 0 ) #[3]
49
+ self .tail = Node (0 , 0 ) #[3]
50
+ self .head .next = self .tail
51
+ self .tail .prev = self .head
52
+
53
+ def remove (self , node ):
54
+ node .prev .next = node .next
55
+ node .next .prev = node .prev
56
+
57
+ def promote (self , node ): #[1]
58
+ #set the node next to head
59
+ temp = self .head .next
60
+ node .next = temp
61
+ temp .prev = node
62
+ self .head .next = node
63
+ node .prev = self .head
64
+
65
+ def get (self , key ):
66
+ if key in self .dic :
67
+ node = self .dic [key ]
68
+ self .remove (node )
69
+ self .promote (node )
70
+ return node .val
71
+ return - 1
72
+
73
+ def put (self , key , value ):
74
+ if key in self .dic :
75
+ self .remove (self .dic [key ])
76
+ node = Node (key , value )
77
+ self .promote (node )
78
+ self .dic [key ] = node
79
+
80
+ if len (self .dic )> self .capacity : #[2]
81
+ del self .dic [self .tail .prev .key ]
82
+ self .remove (self .tail .prev )
83
+
84
+ #using OrderedDict()
85
+ class LRUCache (object ):
86
+ def __init__ (self , capacity ):
87
+ self .dic = collections .OrderedDict ()
88
+ self .remain = capacity
89
+
90
+ def get (self , key ):
91
+ if key not in self .dic :
92
+ return - 1
93
+ v = self .dic .pop (key )
94
+ self .dic [key ] = v # set key as the newest one
95
+ return v
96
+
97
+ def set (self , key , value ):
98
+ if key in self .dic :
99
+ self .dic .pop (key )
100
+ else :
101
+ if self .remain > 0 :
102
+ self .remain -= 1
103
+ else : # self.dic is full
104
+ self .dic .popitem (last = False )
105
+ self .dic [key ] = value
0 commit comments