-
LRU Cache (least recently used)
multi-level cache in CPU
LRU: Hash Table + Double Linked List
Time complexity: O(1) lookup, O(1) update/modify
-
146. LRU Cache
Design a data structure that follows the constraints of a Least Recently Used (LRU) cache.
Implement the
LRUCache
class:LRUCache(int capacity)
Initialize the LRU cache with positive sizecapacity
.int get(int key)
Return the value of thekey
if the key exists, otherwise return-1
.void put(int key, int value)
Update the value of thekey
if thekey
exists. Otherwise, add thekey-value
pair to the cache. If the number of keys exceeds thecapacity
from this operation, evict the least recently used key.
Follow up:
Could you doget
andput
inO(1)
time complexity?Example 1:
Input ["LRUCache", "put", "put", "get", "put", "get", "put", "get", "get", "get"] [[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]] Output [null, null, null, 1, null, -1, null, -1, 3, 4] Explanation LRUCache lRUCache = new LRUCache(2); lRUCache.put(1, 1); // cache is {1=1} lRUCache.put(2, 2); // cache is {1=1, 2=2} lRUCache.get(1); // return 1 lRUCache.put(3, 3); // LRU key was 2, evicts key 2, cache is {1=1, 3=3} lRUCache.get(2); // returns -1 (not found) lRUCache.put(4, 4); // LRU key was 1, evicts key 1, cache is {4=4, 3=3} lRUCache.get(1); // return -1 (not found) lRUCache.get(3); // return 3 lRUCache.get(4); // return 4
Constraints:
1 <= capacity <= 3000
0 <= key <= 3000
0 <= value <= 104
- At most
3 * 104
calls will be made toget
andput
.
class LRUCache { class DLinkedNode { int key; int value; DLinkedNode pre; DLinkedNode next; public DLinkedNode () { } public DLinkedNode (int key, int value) { this.key = key; this.value = value; } } private Map<Integer, DLinkedNode> cache = new HashMap<>(); private int size; private int cap; private DLinkedNode head, tail; public LRUCache(int capacity) { this.size = 0; this.cap = capacity; head = new DLinkedNode(); tail = new DLinkedNode(); head.next = tail; tail.pre = head; } public int get(int key) { DLinkedNode node = cache.get(key); if (node == null) { return -1; } moveToHead(node); return node.value; } public void put(int key, int value) { DLinkedNode node = cache.get(key); if (node == null) { DLinkedNode newNode = new DLinkedNode(key, value); cache.put(key, newNode); addToHead(newNode); size++; if (size > cap) { DLinkedNode tail = removeTail(); cache.remove(tail.key); size--; } } else { node.value = value; moveToHead(node); } } private void moveToHead(DLinkedNode node) { removeNode(node); addToHead(node); } private void removeNode(DLinkedNode node) { node.pre.next = node.next; node.next.pre = node.pre; } private void addToHead(DLinkedNode node) { node.pre = head; node.next = head.next; head.next.pre = node; head.next = node; } private DLinkedNode removeTail() { DLinkedNode res = tail.pre; removeNode(res); return res; } }
-
Bloom Filter
套在外层的缓存!
一个很长的二进制向量和一系列随机映射函数。
布隆过滤器可以用于检索一个元素是否在一个集合中。
优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难。
只要有一个映射位是0,元素一定不存在;映射位都是1也不一定存在,存在误差。
案例:
- 比特币网络
- 分布式系统(Map-Reduce) - Hadoop、search engine
- Redis缓存
- 垃圾邮件、评论等的过滤
-
Sort
重点:堆排序,快速排序,归并排序
归并:先排序左右子数组,然后合并两个有序子数组
快排:先调配出左右子数组,然后对于左右子数组进行排序 -
1122. Relative Sort Array
Given two arrays
arr1
andarr2
, the elements ofarr2
are distinct, and all elements inarr2
are also inarr1
.Sort the elements of
arr1
such that the relative ordering of items inarr1
are the same as inarr2
. Elements that don't appear inarr2
should be placed at the end ofarr1
in ascending order.Example 1:
Input: arr1 = [2,3,1,3,2,4,6,7,9,2,19], arr2 = [2,1,4,3,9,6] Output: [2,2,2,1,4,3,3,9,6,7,19]
Constraints:
1 <= arr1.length, arr2.length <= 1000
0 <= arr1[i], arr2[i] <= 1000
- All the elements of
arr2
are distinct. - Each
arr2[i]
is inarr1
.
class Solution { public int[] relativeSortArray(int[] arr1, int[] arr2) { int i = 0; for (int i2 = 0; i2 < arr2.length; i2++) { for (int i1 = 0; i1 < arr1.length; i1++) { if (arr1[i1] == arr2[i2]) { int t = arr1[i]; arr1[i++] = arr1[i1]; arr1[i1] = t; } } } Arrays.sort(arr1, i, arr1.length); return arr1; } }
-
56. Merge Intervals
Given an array of
intervals
whereintervals[i] = [starti, endi]
, merge all overlapping intervals, and return an array of the non-overlapping intervals that cover all the intervals in the input.Example 1:
Input: intervals = [[1,3],[2,6],[8,10],[15,18]] Output: [[1,6],[8,10],[15,18]] Explanation: Since intervals [1,3] and [2,6] overlaps, merge them into [1,6].
Example 2:
Input: intervals = [[1,4],[4,5]] Output: [[1,5]] Explanation: Intervals [1,4] and [4,5] are considered overlapping.
Constraints:
1 <= intervals.length <= 104
intervals[i].length == 2
0 <= starti <= endi <= 104
class Solution { public int[][] merge(int[][] intervals) { Deque<int[]> deque = new LinkedList<>(); Arrays.sort(intervals, (x,y)->(x[1]-y[1])); Arrays.sort(intervals, (x,y)->(x[0]-y[0])); for (int[] interval : intervals) { if (deque.isEmpty()) { deque.addLast(interval); continue; } int end = deque.peekLast()[1]; if (interval[0] <= end) { deque.peekLast()[1] = Math.max(end, interval[1]); } else { deque.addLast(interval); } } int n = deque.size(); int[][] res = new int[n][2]; for (int i = 0; i < n; i++) { res[i] = deque.pollFirst(); } return res; } }
-
493. Reverse Pairs
Given an array
nums
, we call(i, j)
an *important reverse pair* ifi < j
andnums[i] > 2*nums[j]
.You need to return the number of important reverse pairs in the given array.
Example1:
Input: [1,3,2,3,1] Output: 2
Example2:
Input: [2,4,3,5,1] Output: 3
Note:
- The length of the given array will not exceed
50,000
. - All the numbers in the input array are in the range of 32-bit integer.
class Solution { int res = 0; public int reversePairs(int[] nums) { mergeSort(nums, 0, nums.length - 1); return res; } private void mergeSort(int[] nums, int left, int right) { if (right <= left) return ; int mid = (right - left) / 2 + left; mergeSort(nums, left, mid); mergeSort(nums, mid + 1, right); merge(nums, left, mid, right); } private void merge(int[] nums, int l1, int r1, int r2) { // count res int p = l1, q = r1 + 1; while (p <= r1 && q <= r2) { if (nums[p] > (long) nums[q] * 2) { res += r1 - p + 1; q++; } else p++; } int[] arr = new int[r2 - l1 + 1]; int start = l1, i = 0, l2 = r1 + 1; while (l1 <= r1 && l2 <= r2) { arr[i++] = nums[l1] > nums[l2] ? nums[l2++] : nums[l1++]; } while (l1 <= r1) arr[i++] = nums[l1++]; while (l2 <= r2) arr[i++] = nums[l2++]; for (l1 = start; l1 <= r2; l1++) { nums[l1] = arr[l1 - start]; } } }
- The length of the given array will not exceed