拓展算法题Day05-链表lc100:LRU、合并k个升序链表、合并两个有序链表

LRU缓存

  1. LRU:是一种内存淘汰算法,内存大小是有限的,当容量不足时,需要淘汰一些元素,以便新元素可以添加进来。Least Recently Used,最近使用过的数据,是有用的数据,需要留下来。
  2. 算法的数据结构:capacity容量,LinkedHashMap,链表有顺序之分,可以区分最近插入和最远插入,hashMap插入和删除都是O(1);hashMap用来存储键值对(key,Node),链表用来存储元素。
  3. 写一个getNode方法,只要需要操作这个元素,就需要先getNode这个元素,getNode的时候,将这个节点移到最前面(删除node再插入首部)。
  4. 其他方法:添加到首部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;
}

排序链表

归并排序的运用

posted @ 2025-07-15 23:18  AAqqs  阅读(4)  评论(0)    收藏  举报