拓展算法题Day05-链表lc100:LRU、合并k个升序链表、合并两个有序链表
LRU缓存
- LRU:是一种内存淘汰算法,内存大小是有限的,当容量不足时,需要淘汰一些元素,以便新元素可以添加进来。Least Recently Used,最近使用过的数据,是有用的数据,需要留下来。
- 算法的数据结构:capacity容量,LinkedHashMap,链表有顺序之分,可以区分最近插入和最远插入,hashMap插入和删除都是O(1);hashMap用来存储键值对(key,Node),链表用来存储元素。
- 写一个getNode方法,只要需要操作这个元素,就需要先getNode这个元素,getNode的时候,将这个节点移到最前面(删除node再插入首部)。
- 其他方法:添加到首部addFirst;移除尾部元素removeLast;删除节点deleteNode。
public class LRUCache {
private int capacity;
private HashMap<Integer,Node> keyMap = new HashMap<>();
private Node dummy;
public LRUCache(int cap){
this.capacity = cap;
dummy = new Node(0,0);
dummy.pre = dummy;
dummy.next = dummy;
}
public void put(int key,int val){
Node node = getNode(key);
if(node != null) {
node.setVal(val);
return;
}
if(keyMap.size() >= capacity) {
removeLast();
}
addFirst(new Node(key,val));
}
public int get(int key){
Node node = getNode(key);
return node == null ? -1:node.getVal();
}
public Node getNode(int key) {
Node node = keyMap.get(key);
if(node == null) {
return null;
}
//将get的节点放到最前面
deleteNode(node);
addFirst(node);
return node;
}
public void deleteNode(Node node) {
Node pre = node.pre;
Node next = node.next;
if(pre != null) {
pre.next = next;
}
if(next != null){
next.pre = pre;
}
keyMap.remove(node.getKey());
}
public void addFirst(Node node) {
node.next = dummy.next;
node.pre = dummy;
dummy.next.pre = node;
dummy.next = node;
keyMap.put(node.getKey(),node);
}
public void removeLast() {
Node node = dummy.pre;
deleteNode(node);
}
}
合并k个升序链表、合并两个有序链表
最小堆
java可以直接使用PriorityQueue<ListNode>来实现,这个队列可以实现排序的功能。先把所有链表的头节点放进去,然后看哪个最小取出来放到新链表里面(dummy),然后将这个节点的next加入队列,一直循环,直到队列为空。
public ListNode mergeKLists(ListNode[] lists) {
PriorityQueue<ListNode> queue = new PriorityQueue<>((a,b) -> (a.val - b.val));
for(ListNode head : lists) {
if(head != null) {
queue.add(head);
}
}
ListNode dummy = new ListNode(0);
ListNode n = dummy;
while(queue.size() != null) {
ListNode node = queue.poll();
n.next = node;
n = node;
if(node.next != null) {
queue.add(node.next);
}
}
return dummy.next;
}
分治
这里只学习递归的方法,但是运行时超时了,这里写一下代码(主要也是回顾一下合并两个有序链表的方法)
public ListNode mergeKLists(ListNode[] lists) {
return mergeLists(lists,0,lists.length);
}
public ListNode mergeKLists(ListNode[] lists,int i,int j) {
//合并[i,j)
int m = j - i;
if(m == 0) {
return null;
}
if(m == 1) {
return lists[i];
}
//合并左右两边
ListNode left = mergeKLists(lists,i,i+m/2);
ListNode right = mergeKLists(lists,i+m/2,j);
//合并两个有序链表
return mergeTwoLists(left,right);
}
private ListNode mergeTwoLists(ListNode list1,ListNode list2) {
ListNode dummy = new ListNode(0);
ListNode cur = dummy;
while(list1 != null && list2 != null) {
if(list1.val < list2.val) {
cur.next = list1;
cur = list1;
list1 = list1.next;
} else {
cur.next = list2;
cur = list2;
list2 = list2.next;
}
}
while(list1 != null) {
cur.next = list1;
cur = list1;
list1 = list1.next;
}
while(list2 != null) {
cur.next = list2;
cur = list2;
list2 = list2.next;
}
return dummy.next;
}
浙公网安备 33010602011771号