public class LRUCache {
private class Node{
int key;
int value;
Node prev;
Node next;
public Node(int key, int value){
this.key = key;
this.value = value;
}
}
private int capacity;
private HashMap<Integer, Node> map;
// Head : Most recently used
private Node dummyHead;
// Tail : Least recently used
private Node dummyTail;
public LRUCache(int capacity) {
this.capacity = capacity;
this.map = new HashMap<Integer, Node>();
dummyHead = new Node(-1,-1);
dummyTail = new Node(-1,-1);
dummyHead.next = dummyTail;
dummyTail.prev = dummyHead;
}
public int get(int key) {
if(!map.containsKey(key)) return -1;
// Get current node
Node node = map.get(key);
// Disconnect it from the linkedlist
node.prev.next = node.next;
node.next.prev = node.prev;
// Move it to the front
moveToFront(node);
// Return value
return node.value;
}
public void set(int key, int value) {
if(map.containsKey(key)){
// Get current node
Node node = map.get(key);
// Disconnect it from the linkedlist
node.prev.next = node.next;
node.next.prev = node.prev;
// Move it to the front
moveToFront(node);
// set value
node.value = value;
} else {
if(map.size() >= capacity){
// Remove LRU element and its key
removeLRU();
}
// Create new node
Node node = new Node(key, value);
// Save its key in map
map.put(key, node);
// Move it to the front
moveToFront(node);
}
}
private void moveToFront(Node node){
Node oldHead = dummyHead.next;
// Connect node to dummyHead
dummyHead.next = node;
node.prev = dummyHead;
// Connect node to oldHead
node.next = oldHead;
oldHead.prev = node;
}
private void removeLRU(){
Node node = dummyTail.prev;
// Disconnect node from linkedlist
node.prev.next = node.next;
node.next.prev = node.prev;
// Set null of its pointers
node.next = null;
node.prev = null;
// Remove its key from hashmap
map.remove(node.key);
}
}
public class MedianFinder {
// max heap stores all elements smaller / equal to median
PriorityQueue<Integer> maxHeap = new PriorityQueue<Integer>(Collections.reverseOrder());
// min heap stores all elements bigger / equal to median
PriorityQueue<Integer> minHeap = new PriorityQueue<Integer>();
// Adds a number into the data structure.
public void addNum(int num) {
// Check heap top
if(maxHeap.size() == 0 || num <= maxHeap.peek()){
maxHeap.offer(num);
} else {
minHeap.offer(num);
}
// min/max heap's size would not differ more than one
// Rebalance if necessary
while(Math.abs(maxHeap.size() - minHeap.size()) > 1){
if(maxHeap.size() > minHeap.size()){
minHeap.offer(maxHeap.poll());
} else {
maxHeap.offer(minHeap.poll());
}
}
}
// Returns the median of current data stream
public double findMedian() {
int maxSize = maxHeap.size();
int minSize = minHeap.size();
if(maxSize == minSize) return (double) (maxHeap.peek() + minHeap.peek()) / 2;
if(maxSize - 1 == minSize) return (double) maxHeap.peek();
if(maxSize == minSize - 1) return (double) minHeap.peek();
return 0;
}
};
public class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
if(nums == null || nums.length == 0) return new int[0];
int[] rst = new int[nums.length - k + 1];
// Deque stores indexes of elements i, in descending order of nums[i]
// First : smallet element in current window
// Last : biggest element in current window
Deque<Integer> deque = new LinkedList<>();
for(int i = 0; i < nums.length; i++){
while(!deque.isEmpty() && nums[i] > nums[deque.peekFirst()]){
deque.pollFirst();
}
deque.offerFirst(i);
// element to remove from sliding window
if(i - k == deque.peekLast()) deque.pollLast();
if(i - k + 1 >= 0) rst[i - k + 1] = nums[deque.peekLast()];
}
return rst;
}
}