Skip to content

Commit

Permalink
Merge pull request soapyigu#237 from WAMaker/master
Browse files Browse the repository at this point in the history
 [LinkedList] Add a solution to LRU Cache
  • Loading branch information
soapyigu authored May 4, 2019
2 parents 7a3e77e + c46f4f7 commit 3c42db4
Show file tree
Hide file tree
Showing 3 changed files with 232 additions and 1 deletion.
138 changes: 138 additions & 0 deletions LinkedList/LFUCache.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
/**
* Question Link: https://leetcode.com/problems/lfu-cache/
* Primary idea: Use linked list and hash map to build the cache.
* Time Complexity Per Action: O(1), Space Complexity: O(K)
*
*/

class LFUCache {

private let capacity: Int
private var nodeMap = [Int: CacheNode]()
private var listMap = [Int: CacheList]()
private var size = 0
private var leastFrequency = 1

init(_ capacity: Int) {
self.capacity = capacity
}

func get(_ key: Int) -> Int {
guard let node = nodeMap[key], let list = listMap[node.count] else {
return -1
}
updateExsit(node: node)
return node.val
}

func put(_ key: Int, _ value: Int) {
if capacity == 0 {
return
}

if let node = nodeMap[key], let list = listMap[node.count] {
node.val = value
updateExsit(node: node)
} else {
removeCacheIfNeeded()

let node = CacheNode(key, value)
nodeMap[key] = node
listMap(add: node)

size += 1
leastFrequency = 1
}
}

private func updateExsit(node: CacheNode) {
guard let list = listMap[node.count] else {
return
}
list.remove(node)

if list.isEmpty {
listMap[node.count] = nil

if leastFrequency == node.count {
leastFrequency += 1
}
}

node.count += 1
listMap(add: node)
}

private func removeCacheIfNeeded() {
guard size >= capacity, let list = listMap[leastFrequency], let key = list.removeLast()?.key else {
return
}
size -= 1
nodeMap[key] = nil
if list.isEmpty {
listMap[leastFrequency] = nil
}
}

private func listMap(add node: CacheNode) {
let list = listMap[node.count, default: CacheList()]
list.add(node)
listMap[node.count] = list
}

}

class CacheList {

private let head = CacheNode(0, 0)
private let tail = CacheNode(0, 0)
private var count = 0

var isEmpty: Bool {
return count <= 0
}

init() {
head.next = tail
tail.pre = head
}

func add(_ node: CacheNode) {
head.next?.pre = node
node.next = head.next
node.pre = head
head.next = node
count += 1
}


func remove(_ node: CacheNode) {
node.pre?.next = node.next
node.next?.pre = node.pre
node.next = nil
node.pre = nil
count -= 1
}

func removeLast() -> CacheNode? {
guard !isEmpty, let node = tail.pre else {
return nil
}
remove(node)
return node
}

}

class CacheNode {
let key: Int
var val: Int
var pre: CacheNode?
var next: CacheNode?
var count = 1

init(_ key: Int, _ val: Int) {
self.key = key
self.val = val
}
}
90 changes: 90 additions & 0 deletions LinkedList/LRUCache.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/**
* Question Link: https://leetcode.com/problems/lru-cache/
* Primary idea: Use linked list and hash map to build the cache.
* Time Complexity Per Action: O(1), Space Complexity: O(K)
*
*/

class LRUCache {

private let capacity: Int
private var count = 0

private let head = LRUCacheNode(0, 0)
private let tail = LRUCacheNode(0, 0)

private var dict = [Int: LRUCacheNode]()

init(_ capacity: Int) {
self.capacity = capacity

head.next = tail
tail.pre = head
}

func get(_ key: Int) -> Int {
if let node = dict[key] {
remove(key)
insert(node)
return node.val
}
return -1
}

func put(_ key: Int, _ value: Int) {
if let node = dict[key] {
node.val = value
remove(key)
insert(node)
return
}

let node = LRUCacheNode(key, value)
dict[key] = node
if count == capacity, let tailKey = tail.pre?.key {
remove(tailKey)
}
insert(node)
}

private func insert(_ node: LRUCacheNode) {
dict[node.key] = node

node.next = head.next
head.next?.pre = node
node.pre = head
head.next = node

count += 1
}

private func remove(_ key: Int) {
guard count > 0, let node = dict[key] else {
return
}
dict[key] = nil

node.pre?.next = node.next
node.next?.pre = node.pre
node.pre = nil
node.next = nil

count -= 1
}

}

fileprivate class LRUCacheNode {

let key: Int
var val: Int

var pre: LRUCacheNode?
var next: LRUCacheNode?

init(_ key: Int, _ val: Int) {
self.key = key
self.val = val
}

}
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,8 @@
[Merge Two Sorted Lists](https://leetcode.com/problems/merge-two-sorted-lists/)| [Swift](./LinkedList/MergeTwoSortedLists.swift)| Easy| O(n)| O(1)|
[Merge k Sorted Lists](https://leetcode.com/problems/merge-k-sorted-lists/)| [Swift](./LinkedList/MergeKSortedLists.swift)| Hard| O(mlogn)| O(1)|
[Partition List](https://leetcode.com/problems/partition-list/)| [Swift](./LinkedList/PartitionList.swift)| Medium| O(n)| O(1)|
[LRU Cache](https://leetcode.com/problems/lru-cache/) | [Swift](./LinkedList/LRUCache.swift) | Hard| O(1)| O(1)|
[LFU Cache](https://leetcode.com/problems/lfu-cache/) | [Swift](./LinkedList/LFUCache.swift) | Hard| O(1)| O(1)|

## Stack
| Title | Solution | Difficulty | Time | Space |
Expand Down Expand Up @@ -476,6 +478,7 @@
## Problem Status
| Solution | Number | Title | Difficulty |
| -------- | ------ | ----- | ---------- |
| [Swift](./LinkedList/LFUCache.swift) | 460 | [LFU Cache](https://oj.leetcode.com/problems/lfu-cache/) | Hard |
| [Swift](./DFS/CombinationSumIV.swift) | 377 | [Combination Sum IV](https://leetcode.com/problems/combination-sum-iv/) | Medium
| | 376 | [Wiggle Subsequence](https://leetcode.com/problems/wiggle-subsequence/) | Medium
| [Swift](./DP/GuessNumberHigherOrLowerII.swift) | 375 | [Guess Number Higher or Lower II](https://leetcode.com/problems/guess-number-higher-or-lower-ii/) | Medium
Expand Down Expand Up @@ -690,7 +693,7 @@
| | 149 | [Max Points on a Line](https://oj.leetcode.com/problems/max-points-on-a-line/) | Hard |
| | 148 | [Sort List](https://oj.leetcode.com/problems/sort-list/) | Medium |
| | 147 | [Insertion Sort List](https://oj.leetcode.com/problems/insertion-sort-list/) | Medium |
| | 146 | [LRU Cache](https://oj.leetcode.com/problems/lru-cache/) | Hard |
| [Swift](./LinkedList/LRUCache.swift) | 146 | [LRU Cache](https://oj.leetcode.com/problems/lru-cache/) | Hard |
| [Swift](./Stack/PostorderTraversal.swift) | 145 | [Binary Tree Postorder Traversal](https://oj.leetcode.com/problems/binary-tree-postorder-traversal/) | Hard |
| [Swift](./Stack/PreorderTraversal.swift) | 144 | [Binary Tree Preorder Traversal](https://oj.leetcode.com/problems/binary-tree-preorder-traversal/) | Medium |
| [Swift](./LinkedList/ReorderList.swift) | 143 | [Reorder List](https://oj.leetcode.com/problems/reorder-list/) | Medium |
Expand Down

0 comments on commit 3c42db4

Please sign in to comment.