提交 fc689f51 编写于 作者: GreyZeng's avatar GreyZeng

uipdate

上级 07e8f4f6
/*
* Design and implement a data structure for a Least Frequently Used (LFU) cache. Implement the
* LFUCache class:
*
* LFUCache(int capacity) Initializes the object with the capacity of the data structure. int
* get(int key) Gets the value of the key if the key exists in the cache. Otherwise, returns -1.
* void put(int key, int value) Update the value of the key if present, or inserts the key if not
* already present. When the cache reaches its capacity, it should invalidate and remove the least
* frequently used key before inserting a new item. For this problem, when there is a tie (i.e., two
* or more keys with the same frequency), the least recently used key would be invalidated. To
* determine the least frequently used key, a use counter is maintained for each key in the cache.
* The key with the smallest use counter is the least frequently used key.
*
* When a key is first inserted into the cache, its use counter is set to 1 (due to the put
* operation). The use counter for a key in the cache is incremented either a get or put operation
* is called on it.
*
*
*
* Example 1:
*
* Input ["LFUCache", "put", "put", "get", "put", "get", "get", "put", "get", "get", "get"] [[2],
* [1, 1], [2, 2], [1], [3, 3], [2], [3], [4, 4], [1], [3], [4]] Output [null, null, null, 1, null,
* -1, 3, null, -1, 3, 4]
*
* Explanation // cnt(x) = the use counter for key x // cache=[] will show the last used order for
* tiebreakers (leftmost element is most recent) LFUCache lfu = new LFUCache(2); lfu.put(1, 1); //
* cache=[1,_], cnt(1)=1 lfu.put(2, 2); // cache=[2,1], cnt(2)=1, cnt(1)=1 lfu.get(1); // return 1
* // cache=[1,2], cnt(2)=1, cnt(1)=2 lfu.put(3, 3); // 2 is the LFU key because cnt(2)=1 is the
* smallest, invalidate 2. // cache=[3,1], cnt(3)=1, cnt(1)=2 lfu.get(2); // return -1 (not found)
* lfu.get(3); // return 3 // cache=[3,1], cnt(3)=2, cnt(1)=2 lfu.put(4, 4); // Both 1 and 3 have
* the same cnt, but 1 is LRU, invalidate 1. // cache=[4,3], cnt(4)=1, cnt(3)=2 lfu.get(1); //
* return -1 (not found) lfu.get(3); // return 3 // cache=[3,4], cnt(4)=1, cnt(3)=3 lfu.get(4); //
* return 4 // cache=[3,4], cnt(4)=2, cnt(3)=3
*
*
* Constraints:
*
* 0 <= capacity, key, value <= 10^4 At most 10^5 calls will be made to get and put.
*
*
* Follow up: Could you do both operations in O(1) time complexity?
*/
package 数据结构.LFU;
import java.util.HashMap;
// TODO
// https://leetcode.com/problems/lfu-cache/
// tips
// 优先看词频,词频一样的,删除最早的纪录
// 同样词频的数据只会进一个桶
// 桶内双向链表,桶之间也是双向链表
// tips:
// Put/Get方法都用O(1)
// 二维双向链表
// map1 : str->node
// map2: node->bucket(频度为n的桶)
public class LeetCode_0460_LFUCache {
static class LFUCache {
public LFUCache(int K) {
capacity = K;
size = 0;
records = new HashMap<>();
heads = new HashMap<>();
headList = null;
}
private int capacity; // 缓存的大小限制,即K
private int size; // 缓存目前有多少个节点
private HashMap<Integer, Node> records;// 表示key(Integer)由哪个节点(Node)代表
private HashMap<Node, NodeList> heads; // 表示节点(Node)在哪个桶(NodeList)里
private NodeList headList; // 整个结构中位于最左的桶
// 节点的数据结构
public static class Node {
public Integer key;
public Integer value;
public Integer times; // 这个节点发生get或者set的次数总和
public Node up; // 节点之间是双向链表所以有上一个节点
public Node down;// 节点之间是双向链表所以有下一个节点
public Node(int k, int v, int t) {
key = k;
value = v;
times = t;
}
}
// 桶结构
public static class NodeList {
public Node head; // 桶的头节点
public Node tail; // 桶的尾节点
public NodeList last; // 桶之间是双向链表所以有前一个桶
public NodeList next; // 桶之间是双向链表所以有后一个桶
public NodeList(Node node) {
head = node;
tail = node;
}
// 把一个新的节点加入这个桶,新的节点都放在顶端变成新的头部
public void addNodeFromHead(Node newHead) {
newHead.down = head;
head.up = newHead;
head = newHead;
}
// 判断这个桶是不是空的
public boolean isEmpty() {
return head == null;
}
// 删除node节点并保证node的上下环境重新连接
public void deleteNode(Node node) {
if (head == tail) {
head = null;
tail = null;
} else {
if (node == head) {
head = node.down;
head.up = null;
} else if (node == tail) {
tail = node.up;
tail.down = null;
} else {
node.up.down = node.down;
node.down.up = node.up;
}
}
node.up = null;
node.down = null;
}
}
// removeNodeList:刚刚减少了一个节点的桶
// 这个函数的功能是,判断刚刚减少了一个节点的桶是不是已经空了。
// 1)如果不空,什么也不做
//
// 2)如果空了,removeNodeList还是整个缓存结构最左的桶(headList)。
// 删掉这个桶的同时也要让最左的桶变成removeNodeList的下一个。
//
// 3)如果空了,removeNodeList不是整个缓存结构最左的桶(headList)。
// 把这个桶删除,并保证上一个的桶和下一个桶之间还是双向链表的连接方式
//
// 函数的返回值表示刚刚减少了一个节点的桶是不是已经空了,空了返回true;不空返回false
private boolean modifyHeadList(NodeList removeNodeList) {
if (removeNodeList.isEmpty()) {
if (headList == removeNodeList) {
headList = removeNodeList.next;
if (headList != null) {
headList.last = null;
}
} else {
removeNodeList.last.next = removeNodeList.next;
if (removeNodeList.next != null) {
removeNodeList.next.last = removeNodeList.last;
}
}
return true;
}
return false;
}
// 函数的功能
// node这个节点的次数+1了,这个节点原来在oldNodeList里。
// 把node从oldNodeList删掉,然后放到次数+1的桶中
// 整个过程既要保证桶之间仍然是双向链表,也要保证节点之间仍然是双向链表
private void move(Node node, NodeList oldNodeList) {
oldNodeList.deleteNode(node);
// preList表示次数+1的桶的前一个桶是谁
// 如果oldNodeList删掉node之后还有节点,oldNodeList就是次数+1的桶的前一个桶
// 如果oldNodeList删掉node之后空了,oldNodeList是需要删除的,所以次数+1的桶的前一个桶,是oldNodeList的前一个
NodeList preList = modifyHeadList(oldNodeList) ? oldNodeList.last : oldNodeList;
// nextList表示次数+1的桶的后一个桶是谁
NodeList nextList = oldNodeList.next;
if (nextList == null) {
NodeList newList = new NodeList(node);
if (preList != null) {
preList.next = newList;
}
newList.last = preList;
if (headList == null) {
headList = newList;
}
heads.put(node, newList);
} else {
if (nextList.head.times.equals(node.times)) {
nextList.addNodeFromHead(node);
heads.put(node, nextList);
} else {
NodeList newList = new NodeList(node);
if (preList != null) {
preList.next = newList;
}
newList.last = preList;
newList.next = nextList;
nextList.last = newList;
if (headList == nextList) {
headList = newList;
}
heads.put(node, newList);
}
}
}
public void put(int key, int value) {
if (capacity == 0) {
return;
}
if (records.containsKey(key)) {
Node node = records.get(key);
node.value = value;
node.times++;
NodeList curNodeList = heads.get(node);
move(node, curNodeList);
} else {
if (size == capacity) {
Node node = headList.tail;
headList.deleteNode(node);
modifyHeadList(headList);
records.remove(node.key);
heads.remove(node);
size--;
}
Node node = new Node(key, value, 1);
if (headList == null) {
headList = new NodeList(node);
} else {
if (headList.head.times.equals(node.times)) {
headList.addNodeFromHead(node);
} else {
NodeList newList = new NodeList(node);
newList.next = headList;
headList.last = newList;
headList = newList;
}
}
records.put(key, node);
heads.put(node, headList);
size++;
}
}
public int get(int key) {
if (!records.containsKey(key)) {
return -1;
}
Node node = records.get(key);
node.times++;
NodeList curNodeList = heads.get(node);
move(node, curNodeList);
return node.value;
}
}
}
package 数据结构.LRU;
import java.util.HashMap;
// 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 size capacity.
// int get(int key) Return the value of the key if the key exists, otherwise return -1.
// void put(int key, int value) Update the value of the key if the key exists. Otherwise, add the
// key-value pair to the cache.
// If the number of keys exceeds the capacity from this operation, evict the least recently used
// key.
// Follow up:
// Could you do get and put in O(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 to get and put.
// https://www.cnblogs.com/greyzeng/p/14413345.html
public class LeetCode_0146_LRUCache {
public static class LRUCache {
public static class Node {
public int key;
public int value;
public Node last;
public Node next;
public Node(int key, int value) {
this.key = key;
this.value = value;
}
}
public static class DoubleLinkedList {
public Node head;
public Node tail;
public DoubleLinkedList() {
head = null;
tail = null;
}
public void moveToLast(Node node) {
if (tail == node) {
return;
}
if (head == node) {
head = node.next;
head.last = null;
} else {
node.last.next = node.next;
node.next.last = node.last;
}
node.last = tail;
node.next = null;
tail.next = node;
tail = node;
}
public void addLast(Node node) {
if (head == null) {
head = node;
tail = node;
}
if (tail != null) {
tail.next = node;
node.last = tail;
tail = node;
}
}
}
private HashMap<Integer, Node> map;
private DoubleLinkedList list;
private final int capacity;
public LRUCache(int capacity) {
this.map = new HashMap<>();
this.list = new DoubleLinkedList();
this.capacity = capacity;
}
/*
* ["LRUCache","put","put","get","put","get","put","get","get","get"]
* [[2],[1,1],[2,2],[1],[3,3],[2],[4,4],[1],[3],[4]]
*
* [null,null,null,1,null,2,null,1,3,4]
*/
// note get值后,需要把这个值设置为最新的未使用的过的值
public int get(int key) {
if (map.containsKey(key)) {
Node node = map.get(key);
list.moveToLast(node);
return node.value;
}
return -1;
}
public void put(int key, int value) {
if (map.containsKey(key)) {
Node old = map.get(key);
old.value = value;
list.moveToLast(old);
} else {
if (map.size() == capacity) {
map.remove(list.head.key);
list.head.value = value;
list.head.key = key;
map.put(key, list.head);
list.moveToLast(list.head);
} else {
Node node = new Node(key, value);
map.put(key, node);
list.addLast(node);
}
}
}
}
public static void main(String[] args) {
LRUCache cache = new LRUCache(2);
cache.put(1, 1);
cache.put(2, 2);
cache.get(1);
cache.put(3, 3);
cache.get(2);
}
}
/* Design and implement a data structure for a Least Frequently Used (LFU) cache. Implement the LFUCache class:
LFUCache(int capacity) Initializes the object with the capacity of the data structure.
int get(int key) Gets the value of the key if the key exists in the cache. Otherwise, returns -1.
void put(int key, int value) Update the value of the key if present, or inserts the key if not already present. When the cache reaches its capacity, it should invalidate and remove the least frequently used key before inserting a new item. For this problem, when there is a tie (i.e., two or more keys with the same frequency), the least recently used key would be invalidated.
To determine the least frequently used key, a use counter is maintained for each key in the cache. The key with the smallest use counter is the least frequently used key.
When a key is first inserted into the cache, its use counter is set to 1 (due to the put operation). The use counter for a key in the cache is incremented either a get or put operation is called on it.
Example 1:
Input
["LFUCache", "put", "put", "get", "put", "get", "get", "put", "get", "get", "get"]
[[2], [1, 1], [2, 2], [1], [3, 3], [2], [3], [4, 4], [1], [3], [4]]
Output
[null, null, null, 1, null, -1, 3, null, -1, 3, 4]
Explanation
// cnt(x) = the use counter for key x
// cache=[] will show the last used order for tiebreakers (leftmost element is most recent)
LFUCache lfu = new LFUCache(2);
lfu.put(1, 1); // cache=[1,_], cnt(1)=1
lfu.put(2, 2); // cache=[2,1], cnt(2)=1, cnt(1)=1
lfu.get(1); // return 1
// cache=[1,2], cnt(2)=1, cnt(1)=2
lfu.put(3, 3); // 2 is the LFU key because cnt(2)=1 is the smallest, invalidate 2.
// cache=[3,1], cnt(3)=1, cnt(1)=2
lfu.get(2); // return -1 (not found)
lfu.get(3); // return 3
// cache=[3,1], cnt(3)=2, cnt(1)=2
lfu.put(4, 4); // Both 1 and 3 have the same cnt, but 1 is LRU, invalidate 1.
// cache=[4,3], cnt(4)=1, cnt(3)=2
lfu.get(1); // return -1 (not found)
lfu.get(3); // return 3
// cache=[3,4], cnt(4)=1, cnt(3)=3
lfu.get(4); // return 4
// cache=[3,4], cnt(4)=2, cnt(3)=3
Constraints:
0 <= capacity, key, value <= 10^4
At most 10^5 calls will be made to get and put.
Follow up: Could you do both operations in O(1) time complexity?*/
package 练习题.leetcode.hard;
import java.util.HashMap;
// TODO
// https://leetcode.com/problems/lfu-cache/
// tips
//优先看词频,词频一样的,删除最早的纪录
// 同样词频的数据只会进一个桶
// 桶内双向链表,桶之间也是双向链表
// tips:
// Put/Get方法都用O(1)
// 二维双向链表
// map1 : str->node
// map2: node->bucket(频度为n的桶)
public class LeetCode_0460_LFUCache {
static class LFUCache {
public LFUCache(int K) {
capacity = K;
size = 0;
records = new HashMap<>();
heads = new HashMap<>();
headList = null;
}
private int capacity; // 缓存的大小限制,即K
private int size; // 缓存目前有多少个节点
private HashMap<Integer, Node> records;// 表示key(Integer)由哪个节点(Node)代表
private HashMap<Node, NodeList> heads; // 表示节点(Node)在哪个桶(NodeList)里
private NodeList headList; // 整个结构中位于最左的桶
// 节点的数据结构
public static class Node {
public Integer key;
public Integer value;
public Integer times; // 这个节点发生get或者set的次数总和
public Node up; // 节点之间是双向链表所以有上一个节点
public Node down;// 节点之间是双向链表所以有下一个节点
public Node(int k, int v, int t) {
key = k;
value = v;
times = t;
}
}
// 桶结构
public static class NodeList {
public Node head; // 桶的头节点
public Node tail; // 桶的尾节点
public NodeList last; // 桶之间是双向链表所以有前一个桶
public NodeList next; // 桶之间是双向链表所以有后一个桶
public NodeList(Node node) {
head = node;
tail = node;
}
// 把一个新的节点加入这个桶,新的节点都放在顶端变成新的头部
public void addNodeFromHead(Node newHead) {
newHead.down = head;
head.up = newHead;
head = newHead;
}
// 判断这个桶是不是空的
public boolean isEmpty() {
return head == null;
}
// 删除node节点并保证node的上下环境重新连接
public void deleteNode(Node node) {
if (head == tail) {
head = null;
tail = null;
} else {
if (node == head) {
head = node.down;
head.up = null;
} else if (node == tail) {
tail = node.up;
tail.down = null;
} else {
node.up.down = node.down;
node.down.up = node.up;
}
}
node.up = null;
node.down = null;
}
}
// removeNodeList:刚刚减少了一个节点的桶
// 这个函数的功能是,判断刚刚减少了一个节点的桶是不是已经空了。
// 1)如果不空,什么也不做
//
// 2)如果空了,removeNodeList还是整个缓存结构最左的桶(headList)。
// 删掉这个桶的同时也要让最左的桶变成removeNodeList的下一个。
//
// 3)如果空了,removeNodeList不是整个缓存结构最左的桶(headList)。
// 把这个桶删除,并保证上一个的桶和下一个桶之间还是双向链表的连接方式
//
// 函数的返回值表示刚刚减少了一个节点的桶是不是已经空了,空了返回true;不空返回false
private boolean modifyHeadList(NodeList removeNodeList) {
if (removeNodeList.isEmpty()) {
if (headList == removeNodeList) {
headList = removeNodeList.next;
if (headList != null) {
headList.last = null;
}
} else {
removeNodeList.last.next = removeNodeList.next;
if (removeNodeList.next != null) {
removeNodeList.next.last = removeNodeList.last;
}
}
return true;
}
return false;
}
// 函数的功能
// node这个节点的次数+1了,这个节点原来在oldNodeList里。
// 把node从oldNodeList删掉,然后放到次数+1的桶中
// 整个过程既要保证桶之间仍然是双向链表,也要保证节点之间仍然是双向链表
private void move(Node node, NodeList oldNodeList) {
oldNodeList.deleteNode(node);
// preList表示次数+1的桶的前一个桶是谁
// 如果oldNodeList删掉node之后还有节点,oldNodeList就是次数+1的桶的前一个桶
// 如果oldNodeList删掉node之后空了,oldNodeList是需要删除的,所以次数+1的桶的前一个桶,是oldNodeList的前一个
NodeList preList = modifyHeadList(oldNodeList) ? oldNodeList.last : oldNodeList;
// nextList表示次数+1的桶的后一个桶是谁
NodeList nextList = oldNodeList.next;
if (nextList == null) {
NodeList newList = new NodeList(node);
if (preList != null) {
preList.next = newList;
}
newList.last = preList;
if (headList == null) {
headList = newList;
}
heads.put(node, newList);
} else {
if (nextList.head.times.equals(node.times)) {
nextList.addNodeFromHead(node);
heads.put(node, nextList);
} else {
NodeList newList = new NodeList(node);
if (preList != null) {
preList.next = newList;
}
newList.last = preList;
newList.next = nextList;
nextList.last = newList;
if (headList == nextList) {
headList = newList;
}
heads.put(node, newList);
}
}
}
public void put(int key, int value) {
if (capacity == 0) {
return;
}
if (records.containsKey(key)) {
Node node = records.get(key);
node.value = value;
node.times++;
NodeList curNodeList = heads.get(node);
move(node, curNodeList);
} else {
if (size == capacity) {
Node node = headList.tail;
headList.deleteNode(node);
modifyHeadList(headList);
records.remove(node.key);
heads.remove(node);
size--;
}
Node node = new Node(key, value, 1);
if (headList == null) {
headList = new NodeList(node);
} else {
if (headList.head.times.equals(node.times)) {
headList.addNodeFromHead(node);
} else {
NodeList newList = new NodeList(node);
newList.next = headList;
headList.last = newList;
headList = newList;
}
}
records.put(key, node);
heads.put(node, headList);
size++;
}
}
public int get(int key) {
if (!records.containsKey(key)) {
return -1;
}
Node node = records.get(key);
node.times++;
NodeList curNodeList = heads.get(node);
move(node, curNodeList);
return node.value;
}
}
}
package 练习题.leetcode.medium;
import java.util.HashMap;
//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 size capacity.
// int get(int key) Return the value of the key if the key exists, otherwise return -1.
// void put(int key, int value) Update the value of the key if the key exists. Otherwise, add the key-value pair to the cache.
// If the number of keys exceeds the capacity from this operation, evict the least recently used key.
// Follow up:
// Could you do get and put in O(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 to get and put.
// https://www.cnblogs.com/greyzeng/p/14413345.html
public class LeetCode_0146_LRUCache {
public static class LRUCache {
public static class Node {
public int key;
public int value;
public Node last;
public Node next;
public Node(int key, int value) {
this.key = key;
this.value = value;
}
}
public static class DoubleLinkedList {
public Node head;
public Node tail;
public DoubleLinkedList() {
head = null;
tail = null;
}
public void moveToLast(Node node) {
if (tail == node) {
return;
}
if (head == node) {
head = node.next;
head.last = null;
} else {
node.last.next = node.next;
node.next.last = node.last;
}
node.last = tail;
node.next = null;
tail.next = node;
tail = node;
}
public void addLast(Node node) {
if (head == null) {
head = node;
tail = node;
}
if (tail != null) {
tail.next = node;
node.last = tail;
tail = node;
}
}
}
private HashMap<Integer, Node> map;
private DoubleLinkedList list;
private final int capacity;
public LRUCache(int capacity) {
this.map = new HashMap<>();
this.list = new DoubleLinkedList();
this.capacity = capacity;
}
/*["LRUCache","put","put","get","put","get","put","get","get","get"]
[[2],[1,1],[2,2],[1],[3,3],[2],[4,4],[1],[3],[4]]
[null,null,null,1,null,2,null,1,3,4]*/
// note get值后,需要把这个值设置为最新的未使用的过的值
public int get(int key) {
if (map.containsKey(key)) {
Node node = map.get(key);
list.moveToLast(node);
return node.value;
}
return -1;
}
public void put(int key, int value) {
if (map.containsKey(key)) {
Node old = map.get(key);
old.value = value;
list.moveToLast(old);
} else {
if (map.size() == capacity) {
map.remove(list.head.key);
list.head.value = value;
list.head.key = key;
map.put(key, list.head);
list.moveToLast(list.head);
} else {
Node node = new Node(key, value);
map.put(key, node);
list.addLast(node);
}
}
}
}
public static void main(String[] args) {
LRUCache cache = new LRUCache(2);
cache.put(1, 1);
cache.put(2, 2);
cache.get(1);
cache.put(3, 3);
cache.get(2);
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册