Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 3e787c6

Browse files
feat(lru-cache): add new implementations
1 parent eac045a commit 3e787c6

File tree

6 files changed

+314
-57
lines changed

6 files changed

+314
-57
lines changed
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/**
2+
* @param {string} s
3+
* @return {number}
4+
*/
5+
function lengthOfLongestSubstring(s) {
6+
let max = 0;
7+
let start = 0;
8+
const map = {};
9+
10+
for (let i = 0; i < s.length; i++) {
11+
const char = s[i];
12+
13+
if (map[char]) {
14+
start = map[char] + 1;
15+
}
16+
17+
map[char] = i;
18+
max = Math.max(1 + i - start, max);
19+
}
20+
21+
return max;
22+
}
23+
24+
const assert = require('assert');
25+
26+
const testCases = { abcabcbb: 3 };
27+
28+
for (const [string, unique] of Object.entries(testCases)) {
29+
assert.equal(lengthOfLongestSubstring(string), unique);
30+
}
31+
32+
/*
33+
Longest string without duplicate chars.
34+
35+
"abcabcbb"
36+
3 (abc)
37+
38+
i=6
39+
c=b
40+
s=5
41+
h={a:3,b:4,c:2}
42+
m=3
43+
44+
---
45+
a
46+
1
47+
48+
aa
49+
1
50+
51+
ab
52+
2
53+
54+
abc
55+
3
56+
57+
aab
58+
2
59+
60+
aabca
61+
3
62+
63+
"dvdf"
64+
3 (vdf)
65+
66+
"abcabcbb"
67+
3 (abc)
68+
---
69+
70+
map: O(n)
71+
backtracking
72+
*/

‎src/data-structures/custom/lru-cache-1.js

Lines changed: 3 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,7 @@
1-
21
/**
3-
* Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations: get and put.
4-
5-
get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.
6-
put(key, value) - Set or insert the value if the key is not already present. When the cache reached its capacity, it should invalidate the least recently used item before inserting a new item.
7-
8-
Follow up:
9-
Could you do both operations in O(1) time complexity?
10-
11-
Example:
12-
13-
LRUCache cache = new LRUCache( 2);
14-
15-
cache.put(1, 1);
16-
cache.put(2, 2);
17-
cache.get(1); // returns 1
18-
cache.put(3, 3); // evicts key 2
19-
cache.get(2); // returns -1 (not found)
20-
cache.put(4, 4); // evicts key 1
21-
cache.get(1); // returns -1 (not found)
22-
cache.get(3); // returns 3
23-
cache.get(4); // returns 4
24-
25-
* https://leetcode.com/problems/lru-cache/description/
26-
*
27-
* @param {number} capacity
2+
* Least Recently Used (LRU) cache.
3+
* Map + Array: O(n)
4+
* @param {number} capacity - Number of items to hold.
285
*/
296
const LRUCache = function (capacity) {
307
this.map = new Map();
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/**
2+
* Least Recently Used (LRU) cache.
3+
* Map + (Hash)Set: O(1)
4+
* @param {number} capacity - Number of items to hold.
5+
*/
6+
var LRUCache = function(capacity) {
7+
this.capacity = capacity || 2;
8+
this.map = new Map();
9+
this.set = new Set();
10+
this.size = 0;
11+
};
12+
13+
/**
14+
* @param {number} key
15+
* @return {number}
16+
*/
17+
LRUCache.prototype.get = function(key) {
18+
if (!this.map.has(key)) return -1;
19+
// move to top
20+
this.set.delete(key);
21+
this.set.add(key);
22+
23+
return this.map.get(key);
24+
};
25+
26+
/**
27+
* @param {number} key
28+
* @param {number} value
29+
* @return {void}
30+
*/
31+
LRUCache.prototype.put = function(key, value) {
32+
this.map.set(key, value);
33+
// move to top
34+
this.set.delete(key);
35+
this.set.add(key);
36+
37+
if (this.set.size > this.capacity) {
38+
const leastUsedKey = this.set.values().next().value;
39+
this.map.delete(leastUsedKey);
40+
this.set.delete(leastUsedKey);
41+
}
42+
43+
this.size = this.map.size;
44+
};
45+
46+
/**
47+
* Your LRUCache object will be instantiated and called as such:
48+
* var obj = new LRUCache(capacity)
49+
* var param_1 = obj.get(key)
50+
* obj.put(key,value)
51+
*/
52+
53+
54+
/*
55+
Implement a hashMap cache with a given capacity that once reach deletes the least used element and store the new one.
56+
57+
---
58+
59+
c = new LRUCache(2);
60+
c.put(1,1);
61+
c.put(2,2);
62+
c.put(3,3); // deletes key 1
63+
64+
c = new LRUCache(2);
65+
c.put(1,1);
66+
c.put(2,2);
67+
c.get(1);
68+
c.put(3,3); // deletes key 2
69+
70+
*/
71+
72+
module.exports = LRUCache;
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
const DLinkedList = require('../linked-lists/linked-list');
2+
/**
3+
* Least Recently Used (LRU) cache.
4+
* Map + Double LinkedList: O(1)
5+
* @param {number} capacity - Number of items to hold.
6+
*/
7+
class LRUCache extends Map {
8+
constructor(capacity) {
9+
super(); // initialize map
10+
this.capacity = capacity;
11+
this.list = new DLinkedList();
12+
}
13+
14+
get(key) {
15+
if (!super.has(key)) { return -1; }
16+
17+
// console.log('get', {key});
18+
const node = super.get(key);
19+
this.moveToHead(key, node);
20+
21+
return node.value.value;
22+
}
23+
24+
put(key, value) {
25+
// console.log('put', {key, value});
26+
let node;
27+
if (super.has(key)) {
28+
node = super.get(key);
29+
node.value.value = value;
30+
} else {
31+
node = this.list.addLast({key, value});
32+
}
33+
this.moveToHead(key, node);
34+
35+
if (this.list.size > this.capacity) {
36+
const firstNode = this.list.removeFirst();
37+
super.delete(firstNode.key);
38+
}
39+
}
40+
41+
moveToHead(key, node) {
42+
// remove node and put it in front
43+
this.list.removeByNode(node);
44+
const newNode = this.list.addLast(node.value);
45+
super.set(key, newNode);
46+
// console.log('\tlist', Array.from(this.list).map(l => l.node.value));
47+
// console.log('\tlist', Array.from(this.list).map(l => l.node.value.key));
48+
}
49+
}
50+
51+
module.exports = LRUCache;

‎src/data-structures/custom/lru-cache.js

Lines changed: 8 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,7 @@
11
/**
2-
* Design and implement a data structure for Least Recently Used (LRU) cache.
3-
* It should support the following operations: get and put.
4-
5-
get(key) - Get the value (will always be positive) of the key
6-
if the key exists in the cache, otherwise return -1.
7-
put(key, value) - Set or insert the value if the key is not already present.
8-
When the cache reached its capacity, it should invalidate the least
9-
recently used item before inserting a new item.
10-
11-
Follow up:
12-
Could you do both operations in O(1) time complexity?
13-
14-
Example:
15-
16-
LRUCache cache = new LRUCache( 2);
17-
18-
cache.put(1, 1);
19-
cache.put(2, 2);
20-
cache.get(1); // returns 1
21-
cache.put(3, 3); // evicts key 2
22-
cache.get(2); // returns -1 (not found)
23-
cache.put(4, 4); // evicts key 1
24-
cache.get(1); // returns -1 (not found)
25-
cache.get(3); // returns 3
26-
cache.get(4); // returns 4
27-
28-
* https://leetcode.com/problems/lru-cache/description/
29-
* https://leetcode.com/submissions/detail/178329173/
30-
*
31-
* @param {number} capacity
2+
* Least Recently Used (LRU) cache.
3+
* (ordered) Map: O(1)
4+
* @param {number} capacity - Number of items to hold.
325
*/
336
class LRUCache {
347
constructor(capacity) {
@@ -53,7 +26,7 @@ class LRUCache {
5326
rotate(key) {
5427
this.moveToTop(key);
5528
while (this.map.size > this.capacity) {
56-
const it = this.map.keys();
29+
const it = this.map.keys();// keys are in insertion order.
5730
this.map.delete(it.next().value);
5831
}
5932
}
@@ -65,6 +38,10 @@ class LRUCache {
6538
this.map.set(key, value);
6639
}
6740
}
41+
42+
get size() {
43+
return this.map.size;
44+
}
6845
}
6946

7047
module.exports = LRUCache;
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
const LRUCache = require('./lru-cache-3');
2+
3+
describe('LRU Cache', () => {
4+
let c;
5+
6+
describe('#constructor', () => {
7+
it('should initialize', () => {
8+
c = new LRUCache();
9+
expect(c).toBeDefined();
10+
});
11+
12+
it('should initialize', () => {
13+
c = new LRUCache(7);
14+
expect(c.capacity).toEqual(7);
15+
});
16+
});
17+
18+
describe('when initialized', () => {
19+
beforeEach(() => {
20+
c = new LRUCache(2);
21+
});
22+
23+
describe('#put', () => {
24+
it('should insert new elements', () => {
25+
c.put(1, 1);
26+
expect(c.size).toEqual(1);
27+
});
28+
29+
it('should update existing element', () => {
30+
c.put(1, 1);
31+
c.put(1, 2);
32+
expect(c.size).toEqual(1);
33+
});
34+
});
35+
36+
describe('#get', () => {
37+
it('should get element', () => {
38+
c.put(1, 1);
39+
expect(c.get(1)).toEqual(1);
40+
});
41+
42+
it('should return -1 for non-existing elements', () => {
43+
expect(c.get(1)).toEqual(-1);
44+
});
45+
46+
it('should not add non-existing number to the top of the list', () => {
47+
c.put(1, 1);
48+
expect(c.get(8)).toEqual(-1);
49+
c.put(2, 2);
50+
expect(c.get(9)).toEqual(-1);
51+
expect(c.get(1)).toEqual(1);
52+
expect(c.get(2)).toEqual(2);
53+
});
54+
55+
it('should return -1 for removed elements', () => {
56+
c.put(1, 1);
57+
c.put(2, 2);
58+
c.put(3, 3);
59+
expect(c.get(1)).toEqual(-1);
60+
});
61+
62+
it('should not remove value if accessed recently', () => {
63+
c.put(1, 1);
64+
c.put(2, 2);
65+
expect(c.get(1)).toEqual(1);
66+
c.put(3, 3);
67+
expect(c.get(1)).toEqual(1);
68+
expect(c.get(2)).toEqual(-1);
69+
});
70+
71+
it('should update a value', () => {
72+
c.put(1, 1);
73+
c.put(1, 2);
74+
expect(c.get(1)).toEqual(2);
75+
});
76+
});
77+
78+
it('should work with size 10', () => {
79+
c = new LRUCache(10);
80+
81+
c.put(10, 13);
82+
c.put(3, 17);
83+
c.put(6, 11);
84+
c.put(10, 5);
85+
c.put(9, 10);
86+
expect(c.get(13)).toEqual(-1);
87+
c.put(2, 19);
88+
expect(c.get(2)).toEqual(19);
89+
expect(c.get(3)).toEqual(17);
90+
c.put(5, 25);
91+
expect(c.get(8)).toEqual(-1);
92+
c.put(9, 22);
93+
c.put(5, 5);
94+
c.put(1, 30);
95+
expect(c.get(11)).toEqual(-1);
96+
c.put(9, 12);
97+
expect(c.get(7)).toEqual(-1);
98+
expect(c.get(5)).toEqual(5);
99+
expect(c.get(8)).toEqual(-1);
100+
expect(c.get(9)).toEqual(12);
101+
c.put(4, 30);
102+
c.put(9, 3);
103+
expect(c.get(9)).toEqual(3);
104+
expect(c.get(10)).toEqual(5);
105+
expect(c.get(10)).toEqual(5);
106+
});
107+
});
108+
});

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /