Skip to content

Commit 95ef7a9

Browse files
authored
Merge pull request #3846 from vansh-codes/lrucache
Added GFG Solution LRU CACHE
2 parents a2c7e4d + 07c782f commit 95ef7a9

File tree

4 files changed

+444
-107
lines changed

4 files changed

+444
-107
lines changed

dsa-problems/gfg-problems/hard/0101-0200.md

+6
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@ export const problems = [
1616
"solutionLink": "/dsa-solutions/gfg-solutions/Hard/0101-0200/binary-tree-to-dll",
1717
"problemName": "Binary Tree to DLL"
1818
},
19+
{
20+
"difficulty": "Hard",
21+
"gfgLink": "https://www.geeksforgeeks.org/problems/lru-cache/1",
22+
"solutionLink": "/dsa-solutions/gfg-solutions/Hard/0101-0200/lru-cache",
23+
"problemName": "LRU Cache"
24+
},
1925
{
2026
"difficulty": "Hard",
2127
"gfgLink": "https://www.geeksforgeeks.org/problems/number-of-turns-in-binary-tree/1",

dsa-solutions/gfg-solutions/Easy problems/square-root.md

+4-16
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,11 @@
11
---
22
id: square-root
33
title: Square Root
4-
sidebar_label: 9 Square Root
4+
sidebar_label: Square-Root
55
tags:
66
- Math
77
- Binary Search
8-
- Python
9-
- Java
10-
- C++
11-
- JavaScript
12-
- TypeScript
13-
description: "This document provides solutions to the problem of finding the square root of a given integer using various programming languages."
8+
description: "This document provides solutions to the problem of finding the Square Root of an integer."
149
---
1510

1611
## Problem
@@ -43,7 +38,7 @@ You don't need to read input or print anything. The task is to complete the func
4338
**Expected Auxiliary Space:** $O(1)$
4439

4540
**Constraints**
46-
- $1 ≤ x ≤ 10^7$
41+
- `1 ≤ x ≤ 10^7`
4742

4843
## Solution
4944

@@ -190,11 +185,4 @@ class Solution {
190185
The provided solutions efficiently find the floor value of the square root of a given integer `x` using binary search. This approach ensures a time complexity of $ O(log N) and an auxiliary space complexity of $O(1)$. The algorithms are designed to handle large values of `x` up to 10^7 efficiently without relying on built-in square root functions.
191186

192187
**Time Complexity:** $O(log N)$
193-
**Auxiliary Space:** $O(1)$
194-
195-
---
196-
197-
## References
198-
199-
- **GeeksforGeeks Problem:** [Square root](https://www.geeksforgeeks.org/problems/square-root/0)
200-
- **Author GeeksforGeeks Profile:** [GeeksforGeeks](https://www.geeksforgeeks.org/user/GeeksforGeeks/)
188+
**Auxiliary Space:** $O(1)$
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,296 @@
1+
---
2+
id: lru-cache
3+
title: LRU Cache
4+
sidebar_label: LRU Cache
5+
6+
tags:
7+
- Linked List
8+
- DLL
9+
- Hash
10+
- Queue
11+
- Design Pattern
12+
- Data Structures
13+
14+
description: "This is a solution to the LRU Cache problem on GeeksForGeeks."
15+
---
16+
17+
## Problem Description
18+
Design a data structure that works like a LRU Cache. Here **cap** denotes the capacity of the cache and Q denotes the number of queries. Query can be of two types:
19+
- **SET x y**: sets the value of the key x with value y
20+
- **GET x**: gets the key of x if present else returns -1.
21+
22+
The LRUCache class has two methods get() and set() which are defined as follows.
23+
- **get(key)**: returns the value of the key if it already exists in the cache otherwise returns -1.
24+
- **set(key, value)**: if the key is already present, update its value. If not present, add the key-value pair to the cache. If the cache reaches its capacity it should invalidate the least recently used item before inserting the new item.
25+
- In the constructor of the class the capacity of the cache should be initialized.
26+
27+
### Examples
28+
29+
**Example 1:**
30+
```
31+
Input:
32+
cap = 2
33+
Q = 2
34+
Queries = SET 1 2 GET 1
35+
36+
Output:
37+
2
38+
39+
Explanation:
40+
Cache Size = 2
41+
42+
SET 1 2 GET 1
43+
SET 1 2 : 1 -> 2
44+
45+
GET 1 : Print the value corresponding
46+
to Key 1, ie 2.
47+
```
48+
49+
**Example 2:**
50+
```
51+
Input:
52+
cap = 2
53+
Q = 8
54+
Queries = SET 1 2 SET 2 3 SET 1 5
55+
SET 4 5 SET 6 7 GET 4 SET 1 2 GET 3
56+
57+
Output:
58+
5 -1
59+
60+
Explanation:
61+
Cache Size = 2
62+
SET 1 2 : 1 -> 2
63+
64+
SET 2 3 : 1 -> 2, 2 -> 3 (the most recently
65+
used one is kept at the rightmost position)
66+
67+
SET 1 5 : 2 -> 3, 1 -> 5
68+
69+
SET 4 5 : 1 -> 5, 4 -> 5 (Cache size is 2, hence
70+
we delete the least recently used key-value pair)
71+
72+
SET 6 7 : 4 -> 5, 6 -> 7
73+
74+
GET 4 : Prints 5 (The cache now looks like
75+
6 -> 7, 4->5)
76+
77+
SET 1 2 : 4 -> 5, 1 -> 2
78+
(Cache size is 2, hence we delete the least
79+
recently used key-value pair)
80+
81+
GET 3 : No key value pair having
82+
key = 3. Hence, -1 is printed.
83+
```
84+
85+
86+
### Constraints
87+
- `1 ≤ Cap ≤ 10^3`
88+
- `1 ≤ Q ≤ 10^5`
89+
- `1 ≤ x,y ≤ 10^4`
90+
91+
92+
## Solution for LRU Cache
93+
### Approach
94+
#### Brute Force
95+
In the brute force approach, we'll use a list to maintain the order of elements and a dictionary to store key-value pairs. This solution will not meet the requirement of O(1) time complexity for both `get()` and `set()` operations but will help in understanding the mechanism.
96+
- **Initialization**: Use a dictionary `cache` to store the key-value pairs and a list order to store the keys in the `order` of their usage.
97+
- **GET Operation:**
98+
- If the key exists in the cache, move the key to the end of the order list (to mark it as recently used) and return the value.
99+
- If the key does not exist, return -1.
100+
- **SET Operation:**
101+
- If the key already exists, update the value and move the key to the end of the `order` list.
102+
- If the key does not exist and the cache is not full, add the key-value pair and append the key to the end of the `order` list.
103+
- If the cache is full, remove the least recently used item (the first item in the `order` list), then add the new key-value pair and append the key to the end of the `order` list.
104+
105+
106+
**Implementation:**
107+
```python
108+
class LRUCache:
109+
def __init__(self, capacity: int):
110+
self.capacity = capacity
111+
self.cache = {}
112+
self.order = []
113+
114+
def get(self, key: int) -> int:
115+
if key in self.cache:
116+
self.order.remove(key)
117+
self.order.append(key)
118+
return self.cache[key]
119+
return -1
120+
121+
def set(self, key: int, value: int) -> None:
122+
if key in self.cache:
123+
self.cache[key] = value
124+
self.order.remove(key)
125+
else:
126+
if len(self.cache) >= self.capacity:
127+
lru = self.order.pop(0)
128+
del self.cache[lru]
129+
self.cache[key] = value
130+
self.order.append(key)
131+
132+
# Example usage
133+
lru_cache = LRUCache(2)
134+
lru_cache.set(1, 2)
135+
print(lru_cache.get(1)) # Output: 2
136+
```
137+
138+
#### Complexity Analysis:
139+
- Time Complexity:
140+
- `get()`: O(n) due to list removal and append operations.
141+
- `set()`: O(n) due to list removal and append operations.
142+
- Space Complexity:
143+
- O(n) where n is the capacity of the cache.
144+
145+
146+
#### Optimized Approach
147+
For an optimized solution, we can use an OrderedDict from the collections module in Python, which maintains the order of insertion and provides O(1) time complexity for both get() and set() operations.
148+
- **Steps**:
149+
- Initialization: Use an OrderedDict to store the key-value pairs and maintain the order of insertion.
150+
- GET Operation:
151+
- If the key exists in the cache, move the key to the end (to mark it as recently used) and return the value.
152+
- If the key does not exist, return -1.
153+
- SET Operation:
154+
- If the key already exists, update the value and move the key to the end.
155+
- If the key does not exist and the cache is not full, add the key-value pair.
156+
- If the cache is full, remove the first item (the least recently used item), then add the new key-value pair.
157+
158+
**Implementation:**
159+
```python
160+
from collections import OrderedDict
161+
162+
class LRUCache:
163+
def __init__(self, capacity: int):
164+
self.cache = OrderedDict()
165+
self.capacity = capacity
166+
167+
def get(self, key: int) -> int:
168+
if key in self.cache:
169+
self.cache.move_to_end(key)
170+
return self.cache[key]
171+
return -1
172+
173+
def set(self, key: int, value: int) -> None:
174+
if key in self.cache:
175+
self.cache.move_to_end(key)
176+
self.cache[key] = value
177+
if len(self.cache) > self.capacity:
178+
self.cache.popitem(last=False)
179+
180+
# Example usage
181+
lru_cache = LRUCache(2)
182+
lru_cache.set(1, 2)
183+
print(lru_cache.get(1)) # Output: 2
184+
```
185+
186+
**Complexity:**
187+
- Time Complexity: O(1) for both `get()` and `set()`.
188+
- Space Complexity: O(n) where n is the capacity of the cache.
189+
190+
**Corner Cases:**
191+
- When the cache is empty, `get()` should return -1 for any key.
192+
- When inserting into a full cache, ensure the least recently used item is removed.
193+
- Ensure `set()` updates the value and position if the key already exists.
194+
- Handling of negative and zero capacity should be considered (though usually, capacity will be a positive integer).
195+
196+
197+
## Code in Different Languages
198+
199+
<Tabs>
200+
201+
<TabItem value="Java" label="Java">
202+
<SolutionAuthor name="@vansh-codes" />
203+
204+
```java
205+
import java.util.LinkedHashMap;
206+
import java.util.Map;
207+
208+
class LRUCache {
209+
private final int capacity;
210+
private final Map<Integer, Integer> cache;
211+
212+
public LRUCache(int capacity) {
213+
this.capacity = capacity;
214+
this.cache = new LinkedHashMap<Integer, Integer>(capacity, 0.75f, true) {
215+
protected boolean removeEldestEntry(Map.Entry eldest) {
216+
return size() > capacity;
217+
}
218+
};
219+
}
220+
221+
public int get(int key) {
222+
return cache.getOrDefault(key, -1);
223+
}
224+
225+
public void set(int key, int value) {
226+
cache.put(key, value);
227+
}
228+
229+
public static void main(String[] args) {
230+
LRUCache lruCache = new LRUCache(2);
231+
lruCache.set(1, 2);
232+
System.out.println(lruCache.get(1)); // Output: 2
233+
}
234+
}
235+
236+
```
237+
238+
</TabItem>
239+
240+
<TabItem value="C++" label="C++">
241+
<SolutionAuthor name="@vansh-codes" />
242+
243+
```cpp
244+
#include <iostream>
245+
#include <unordered_map>
246+
#include <list>
247+
using namespace std;
248+
249+
class LRUCache {
250+
private:
251+
int capacity;
252+
list<pair<int, int>> cache;
253+
unordered_map<int, list<pair<int, int>>::iterator> map;
254+
255+
public:
256+
LRUCache(int capacity) : capacity(capacity) {}
257+
258+
int get(int key) {
259+
if (map.find(key) == map.end()) {
260+
return -1;
261+
} else {
262+
cache.splice(cache.begin(), cache, map[key]);
263+
return map[key]->second;
264+
}
265+
}
266+
267+
void set(int key, int value) {
268+
if (map.find(key) != map.end()) {
269+
cache.splice(cache.begin(), cache, map[key]);
270+
map[key]->second = value;
271+
return;
272+
}
273+
if (cache.size() == capacity) {
274+
int k = cache.back().first;
275+
cache.pop_back();
276+
map.erase(k);
277+
}
278+
cache.push_front({key, value});
279+
map[key] = cache.begin();
280+
}
281+
};
282+
283+
int main() {
284+
LRUCache lruCache(2);
285+
lruCache.set(1, 2);
286+
cout << lruCache.get(1) << endl; // Output: 2
287+
return 0;
288+
}
289+
```
290+
291+
</TabItem>
292+
</Tabs>
293+
294+
## References
295+
296+
- **GeekForGeeks Problem**: [LRU Cache](https://www.geeksforgeeks.org/problems/lru-cache/1)

0 commit comments

Comments
 (0)