- 尝试了下不自定义节点类,使用原生Map和LinkedList来完成,最终超时了。原因是在put操作中,如果put的key原本就存在,那么我们就需要更新map中该key对应的value,同时需要将list中的key移到LinkedList的头部,表示他是最近使用过的key。那么我们就需要先在LinkedList中先删除再addFirst。那么在remove()操作中,时间复杂度是O(n)。而且我暂且也找不到解决方案,因为链表除非在首位删除或增加,否则它的时间复杂度一定是O(n)。
class LRUCache {
Map<Integer, Integer> map;
LinkedList<Integer> list;
int ca;
public LRUCache(int capacity) {
map = new HashMap<>();
list = new LinkedList<>();
ca = capacity;
}
public int get(int key) {
if (map.containsKey(key)) {
list.remove(new Integer(key));
list.addFirst(key);
return map.get(key);
}
return -1;
}
public void put(int key, int value) {
if (map.containsKey(key)) {
map.replace(key, value);
list.remove(new Integer(key));
list.addFirst(key);
return;
} else if (list.size() == ca) {
Integer tmp = list.getLast();
list.removeLast();
map.remove(tmp);
}
list.addFirst(key);
map.put(key, value);
}
}
只能定义一个内部Node类,他是双向链表的节点。put操作的时候先获取当前key对应的Node,移动pre和next指针完成Node的删除,再在链表首部新增Node。符合O(1)的要求。
2. 自定义内部节点类LRUNode
需要注意的是如果超过容量了需要将map中双向链表表尾的节点对应的pair给移除。因为我们判断容量是否达到阈值是根据map的size来判断的,如果仅仅是将链表表尾节点舍弃,而不对map操作,会导致错误。
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
/**
* @ClassName : LRUCache
* @Author : h50021189
* @Date: 2021/9/28 15:50
* @Description :
*/
class LRUCache {
class LRUNode<K, V> {
public K key;
public V value;
public LRUNode next;
public LRUNode pre;
public LRUNode(K key, V value) {
this.key = key;
this.value = value;
}
public V getValue() {
return value;
}
public void setValue(V value) {
this.value = value;
}
}
LRUNode<Integer, Integer> head;
Map<Integer, LRUNode<Integer, Integer>> map;
int capacity;
public LRUCache(int capacity) {
map = new HashMap<>();
this.capacity = capacity;
head = null;
}
public int get(int key) {
if (map.containsKey(key)) {
LRUNode<Integer, Integer> cur = map.get(key);
if (head != cur) {
LRUNode<Integer,Integer> pre = cur.pre;
LRUNode<Integer,Integer> next = cur.next;
pre.next = next;
next.pre = pre;
cur.pre = head.pre;
head.pre.next = cur;
cur.next = head;
head.pre = cur;
head = cur;
}
return cur.getValue();
}
return -1;
}
public void put(int key, int value) {
if (map.containsKey(key)) {
map.get(key).setValue(value);
LRUNode<Integer, Integer> cur = map.get(key);
if (head != cur) {
LRUNode<Integer,Integer> pre = cur.pre;
LRUNode<Integer,Integer> next = cur.next;
pre.next = next;
next.pre = pre;
cur.pre = head.pre;
head.pre.next = cur;
cur.next = head;
head.pre = cur;
head = cur;
}
} else if (map.size() == capacity) {
LRUNode<Integer, Integer> newCreated = new LRUNode(key, value);
map.put(key, newCreated);
map.remove(head.pre.key, head.pre);
newCreated.pre = head.pre.pre;
head.pre.pre.next = newCreated;
head.pre = newCreated;
newCreated.next = head;
head = newCreated;
} else {
if (map.size() == 0) {
LRUNode<Integer, Integer> newCreated = new LRUNode(key, value);
map.put(key, newCreated);
head = newCreated;
head.next = head;
head.pre = head;
} else {
LRUNode<Integer, Integer> newCreated = new LRUNode(key, value);
map.put(key, newCreated);
newCreated.next = head;
newCreated.pre = head.pre;
head.pre.next = newCreated;
head.pre = newCreated;
head = newCreated;
}
}
}
public void read() {
LRUNode node = head;
for (int i = 0; i < map.size() ; i++) {
System.out.print(node.getValue() + " -> ");
node = node.next;
}
System.out.println();
}
public static void main(String[] args) {
LRUCache lruCache = new LRUCache(2);
lruCache.put(1,1);
lruCache.put(2,2);
lruCache.read();
lruCache.get(1);
lruCache.put(3,3);
lruCache.read();
lruCache.get(2);
lruCache.put(4,4);
lruCache.read();
}
}