-
Notifications
You must be signed in to change notification settings - Fork 927
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(lru-cache): add new implementations
- Loading branch information
1 parent
eac045a
commit 3e787c6
Showing
6 changed files
with
314 additions
and
57 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
/** | ||
* @param {string} s | ||
* @return {number} | ||
*/ | ||
function lengthOfLongestSubstring(s) { | ||
let max = 0; | ||
let start = 0; | ||
const map = {}; | ||
|
||
for (let i = 0; i < s.length; i++) { | ||
const char = s[i]; | ||
|
||
if (map[char]) { | ||
start = map[char] + 1; | ||
} | ||
|
||
map[char] = i; | ||
max = Math.max(1 + i - start, max); | ||
} | ||
|
||
return max; | ||
} | ||
|
||
const assert = require('assert'); | ||
|
||
const testCases = { abcabcbb: 3 }; | ||
|
||
for (const [string, unique] of Object.entries(testCases)) { | ||
assert.equal(lengthOfLongestSubstring(string), unique); | ||
} | ||
|
||
/* | ||
Longest string without duplicate chars. | ||
"abcabcbb" | ||
3 (abc) | ||
i=6 | ||
c=b | ||
s=5 | ||
h={a:3,b:4,c:2} | ||
m=3 | ||
--- | ||
a | ||
1 | ||
aa | ||
1 | ||
ab | ||
2 | ||
abc | ||
3 | ||
aab | ||
2 | ||
aabca | ||
3 | ||
"dvdf" | ||
3 (vdf) | ||
"abcabcbb" | ||
3 (abc) | ||
--- | ||
map: O(n) | ||
backtracking | ||
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
/** | ||
* Least Recently Used (LRU) cache. | ||
* Map + (Hash)Set: O(1) | ||
* @param {number} capacity - Number of items to hold. | ||
*/ | ||
var LRUCache = function(capacity) { | ||
this.capacity = capacity || 2; | ||
this.map = new Map(); | ||
this.set = new Set(); | ||
this.size = 0; | ||
}; | ||
|
||
/** | ||
* @param {number} key | ||
* @return {number} | ||
*/ | ||
LRUCache.prototype.get = function(key) { | ||
if (!this.map.has(key)) return -1; | ||
// move to top | ||
this.set.delete(key); | ||
this.set.add(key); | ||
|
||
return this.map.get(key); | ||
}; | ||
|
||
/** | ||
* @param {number} key | ||
* @param {number} value | ||
* @return {void} | ||
*/ | ||
LRUCache.prototype.put = function(key, value) { | ||
this.map.set(key, value); | ||
// move to top | ||
this.set.delete(key); | ||
this.set.add(key); | ||
|
||
if (this.set.size > this.capacity) { | ||
const leastUsedKey = this.set.values().next().value; | ||
this.map.delete(leastUsedKey); | ||
this.set.delete(leastUsedKey); | ||
} | ||
|
||
this.size = this.map.size; | ||
}; | ||
|
||
/** | ||
* Your LRUCache object will be instantiated and called as such: | ||
* var obj = new LRUCache(capacity) | ||
* var param_1 = obj.get(key) | ||
* obj.put(key,value) | ||
*/ | ||
|
||
|
||
/* | ||
Implement a hashMap cache with a given capacity that once reach deletes the least used element and store the new one. | ||
--- | ||
c = new LRUCache(2); | ||
c.put(1,1); | ||
c.put(2,2); | ||
c.put(3,3); // deletes key 1 | ||
c = new LRUCache(2); | ||
c.put(1,1); | ||
c.put(2,2); | ||
c.get(1); | ||
c.put(3,3); // deletes key 2 | ||
*/ | ||
|
||
module.exports = LRUCache; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
const DLinkedList = require('../linked-lists/linked-list'); | ||
/** | ||
* Least Recently Used (LRU) cache. | ||
* Map + Double LinkedList: O(1) | ||
* @param {number} capacity - Number of items to hold. | ||
*/ | ||
class LRUCache extends Map { | ||
constructor(capacity) { | ||
super(); // initialize map | ||
this.capacity = capacity; | ||
this.list = new DLinkedList(); | ||
} | ||
|
||
get(key) { | ||
if (!super.has(key)) { return -1; } | ||
|
||
// console.log('get', {key}); | ||
const node = super.get(key); | ||
this.moveToHead(key, node); | ||
|
||
return node.value.value; | ||
} | ||
|
||
put(key, value) { | ||
// console.log('put', {key, value}); | ||
let node; | ||
if (super.has(key)) { | ||
node = super.get(key); | ||
node.value.value = value; | ||
} else { | ||
node = this.list.addLast({key, value}); | ||
} | ||
this.moveToHead(key, node); | ||
|
||
if (this.list.size > this.capacity) { | ||
const firstNode = this.list.removeFirst(); | ||
super.delete(firstNode.key); | ||
} | ||
} | ||
|
||
moveToHead(key, node) { | ||
// remove node and put it in front | ||
this.list.removeByNode(node); | ||
const newNode = this.list.addLast(node.value); | ||
super.set(key, newNode); | ||
// console.log('\tlist', Array.from(this.list).map(l => l.node.value)); | ||
// console.log('\tlist', Array.from(this.list).map(l => l.node.value.key)); | ||
} | ||
} | ||
|
||
module.exports = LRUCache; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
const LRUCache = require('./lru-cache-3'); | ||
|
||
describe('LRU Cache', () => { | ||
let c; | ||
|
||
describe('#constructor', () => { | ||
it('should initialize', () => { | ||
c = new LRUCache(); | ||
expect(c).toBeDefined(); | ||
}); | ||
|
||
it('should initialize', () => { | ||
c = new LRUCache(7); | ||
expect(c.capacity).toEqual(7); | ||
}); | ||
}); | ||
|
||
describe('when initialized', () => { | ||
beforeEach(() => { | ||
c = new LRUCache(2); | ||
}); | ||
|
||
describe('#put', () => { | ||
it('should insert new elements', () => { | ||
c.put(1, 1); | ||
expect(c.size).toEqual(1); | ||
}); | ||
|
||
it('should update existing element', () => { | ||
c.put(1, 1); | ||
c.put(1, 2); | ||
expect(c.size).toEqual(1); | ||
}); | ||
}); | ||
|
||
describe('#get', () => { | ||
it('should get element', () => { | ||
c.put(1, 1); | ||
expect(c.get(1)).toEqual(1); | ||
}); | ||
|
||
it('should return -1 for non-existing elements', () => { | ||
expect(c.get(1)).toEqual(-1); | ||
}); | ||
|
||
it('should not add non-existing number to the top of the list', () => { | ||
c.put(1, 1); | ||
expect(c.get(8)).toEqual(-1); | ||
c.put(2, 2); | ||
expect(c.get(9)).toEqual(-1); | ||
expect(c.get(1)).toEqual(1); | ||
expect(c.get(2)).toEqual(2); | ||
}); | ||
|
||
it('should return -1 for removed elements', () => { | ||
c.put(1, 1); | ||
c.put(2, 2); | ||
c.put(3, 3); | ||
expect(c.get(1)).toEqual(-1); | ||
}); | ||
|
||
it('should not remove value if accessed recently', () => { | ||
c.put(1, 1); | ||
c.put(2, 2); | ||
expect(c.get(1)).toEqual(1); | ||
c.put(3, 3); | ||
expect(c.get(1)).toEqual(1); | ||
expect(c.get(2)).toEqual(-1); | ||
}); | ||
|
||
it('should update a value', () => { | ||
c.put(1, 1); | ||
c.put(1, 2); | ||
expect(c.get(1)).toEqual(2); | ||
}); | ||
}); | ||
|
||
it('should work with size 10', () => { | ||
c = new LRUCache(10); | ||
|
||
c.put(10, 13); | ||
c.put(3, 17); | ||
c.put(6, 11); | ||
c.put(10, 5); | ||
c.put(9, 10); | ||
expect(c.get(13)).toEqual(-1); | ||
c.put(2, 19); | ||
expect(c.get(2)).toEqual(19); | ||
expect(c.get(3)).toEqual(17); | ||
c.put(5, 25); | ||
expect(c.get(8)).toEqual(-1); | ||
c.put(9, 22); | ||
c.put(5, 5); | ||
c.put(1, 30); | ||
expect(c.get(11)).toEqual(-1); | ||
c.put(9, 12); | ||
expect(c.get(7)).toEqual(-1); | ||
expect(c.get(5)).toEqual(5); | ||
expect(c.get(8)).toEqual(-1); | ||
expect(c.get(9)).toEqual(12); | ||
c.put(4, 30); | ||
c.put(9, 3); | ||
expect(c.get(9)).toEqual(3); | ||
expect(c.get(10)).toEqual(5); | ||
expect(c.get(10)).toEqual(5); | ||
}); | ||
}); | ||
}); |