Skip to content

Commit 138405c

Browse files
committed
Create file
1 parent e3f304a commit 138405c

File tree

1 file changed

+164
-0
lines changed

1 file changed

+164
-0
lines changed

146-LRUCache/146-LRUCache.rs

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
use std::cell::RefCell;
2+
use std::collections::HashMap;
3+
use std::ops::DerefMut;
4+
use std::rc::Rc;
5+
6+
#[derive(Debug, Default)]
7+
struct LinkedListNode {
8+
key: i32,
9+
value: i32,
10+
newer: Option<Rc<RefCell<LinkedListNode>>>,
11+
older: Option<Rc<RefCell<LinkedListNode>>>,
12+
}
13+
14+
#[derive(Default)]
15+
struct LRUCache {
16+
head: Option<Rc<RefCell<LinkedListNode>>>,
17+
tail: Option<Rc<RefCell<LinkedListNode>>>,
18+
/// Key to node map for constant time access to node by key inside list
19+
map: HashMap<i32, Rc<RefCell<LinkedListNode>>>,
20+
capacity: usize,
21+
}
22+
23+
fn move_to_head(
24+
head: &mut Option<Rc<RefCell<LinkedListNode>>>,
25+
tail: &mut Option<Rc<RefCell<LinkedListNode>>>,
26+
node_ref: &mut Rc<RefCell<LinkedListNode>>,
27+
) {
28+
let mut borrowed = node_ref.borrow_mut();
29+
let LinkedListNode { newer, older, .. } = borrowed.deref_mut();
30+
match (older.is_some(), newer.is_some()) {
31+
// It is already head
32+
(_, false) => {}
33+
// It is tail
34+
(false, _) => {
35+
// Reconnect tail to next item, now newer contains old tail
36+
std::mem::swap(tail, newer);
37+
// Steal link to old tail from new tail and put it to old head
38+
let stollen_link = tail.as_mut().unwrap().borrow_mut().older.take();
39+
head.as_mut().unwrap().borrow_mut().newer = stollen_link;
40+
// Now moved node will point to old head and head will point to None
41+
std::mem::swap(older, head);
42+
// Reconnect old tail node to head
43+
std::mem::swap(head, newer);
44+
}
45+
// It is somewhere in between head and tail
46+
_ => {
47+
// Invalidate older link (move its value to newer node's link to older)
48+
std::mem::swap(older, &mut newer.as_mut().unwrap().borrow_mut().older);
49+
let mut newer_clone = newer.clone();
50+
// At this stage neighbors are pointing to each other, and newer_clone is pointing to node_ref
51+
std::mem::swap(
52+
&mut newer_clone,
53+
&mut newer
54+
.as_mut()
55+
.unwrap()
56+
.borrow_mut()
57+
.older
58+
.as_mut()
59+
.unwrap()
60+
.borrow_mut()
61+
.newer,
62+
);
63+
// Let's finally put it to head (older now points to old head)
64+
std::mem::swap(head, older);
65+
// New head have no newer nodes
66+
*newer = None;
67+
// Old head should point to new head
68+
std::mem::swap(&mut older.as_mut().unwrap().borrow_mut().newer, &mut newer_clone);
69+
}
70+
}
71+
}
72+
73+
/**
74+
* `&self` means the method takes an immutable reference.
75+
* If you need a mutable reference, change it to `&mut self` instead.
76+
*/
77+
impl LRUCache {
78+
fn new(capacity: i32) -> Self {
79+
let capacity = capacity as usize;
80+
Self {
81+
map: HashMap::with_capacity(capacity),
82+
capacity,
83+
..Default::default()
84+
}
85+
}
86+
87+
// Also updates recentness of usage
88+
fn get(&mut self, key: i32) -> i32 {
89+
let LRUCache {
90+
head, tail, map, ..
91+
} = self;
92+
if let Some(node_ref) = map.get_mut(&key) {
93+
let value = node_ref.borrow().value;
94+
move_to_head(head, tail, node_ref);
95+
value
96+
} else {
97+
-1
98+
}
99+
}
100+
101+
fn put(&mut self, key: i32, value: i32) {
102+
let LRUCache {
103+
head,
104+
tail,
105+
map,
106+
capacity,
107+
} = self;
108+
if let Some(node_ref) = map.get_mut(&key) {
109+
node_ref.borrow_mut().value = value;
110+
move_to_head(head, tail, node_ref);
111+
} else {
112+
if map.len() == *capacity {
113+
// Should remove old node before add
114+
// 1. Detaching the oldest node from list
115+
let mut node = tail.as_mut().unwrap().borrow_mut().newer.take();
116+
// 2. Point tail to newer node, while detached node should be in `node`
117+
std::mem::swap(tail, &mut node);
118+
// 3. Drop node from `map`
119+
map.remove(dbg!(&node.as_mut().unwrap().borrow().key));
120+
if tail.is_some() {
121+
// 4. Node from list should be forgotten at the end of scope => drop last link to it
122+
tail.as_mut().unwrap().borrow_mut().older = None;
123+
}
124+
}
125+
if map.is_empty() {
126+
// First node is head and tail at same time
127+
let node = Rc::new(RefCell::new(LinkedListNode {
128+
key,
129+
value,
130+
..Default::default()
131+
}));
132+
map.insert(key, node.clone());
133+
*head = Some(node.clone());
134+
*tail = Some(node);
135+
} else {
136+
// Otherwise connect to head as the most fresh
137+
let node = Rc::new(RefCell::new(LinkedListNode {
138+
key,
139+
value,
140+
older: head.take(),
141+
..Default::default()
142+
}));
143+
let link_for_previous_head = node.clone();
144+
node.borrow_mut()
145+
.older
146+
.as_mut()
147+
.unwrap()
148+
.borrow_mut()
149+
.newer
150+
.replace(link_for_previous_head);
151+
map.insert(key, node.clone());
152+
// Reinitialize head (it is None after previous action) by node as new head.
153+
*head = Some(node);
154+
}
155+
}
156+
}
157+
}
158+
159+
/**
160+
* Your LRUCache object will be instantiated and called as such:
161+
* let obj = LRUCache::new(capacity);
162+
* let ret_1: i32 = obj.get(key);
163+
* obj.put(key, value);
164+
*/

0 commit comments

Comments
 (0)