必备知识
链表是一种兼具递归和迭代性质的数据结构,常用技巧:双指针中的快慢指针。
一、合并两个有序链表(虚拟头结点)
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode mergeTwoLists(ListNod
e list1, ListNode list2) {
ListNode result = new ListNode();// 使用虚拟头结点:第一个节点为空,从第二个节点开始才是想要的
ListNode p = result;
ListNode p1 = list1,p2 = list2;
while(p1 != null && p2!=null) {
if(p1.val > p2.val) {
p.next = p2;
p2 = p2.next;
} else {
p.next = p1;
p1 = p1.next;
}
p = p.next;
}
while(p1 != null) {
p.next = p1;
p1 = p1.next;
p = p.next;
}
while (p2 != null) {
p.next = p2;
p2= p2.next;
p = p.next;
}
return result.next;
}
}
解题思路:
合并两个单链表:
1.使用双指针循环遍历,两个单链表同时遍历比较;然后移动指针
2.两个单链表同时遍历完后,最多会剩下一个单链表还有值,需要将剩下的也合并。
3.两个单链表都需要判断一下是否为空,不空就合并,最后返回合并后的链表
4.可以使用虚拟头结点进行辅助
二、合并K个有序链表(虚拟头结点和二叉堆)
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
ListNode result = new ListNode();
ListNode temp = result;
if(lists.length == 0) {
return null;
}
PriorityQueue<ListNode> minHead = new PriorityQueue<>(lists.length, Comparator.comparingInt(o -> o.val));
for (ListNode node: lists
) {
if (node != null){
minHead.offer(node);
}
}
while (!minHead.isEmpty()) {
ListNode node = minHead.poll();
temp.next = node;
if (node.next != null) {
minHead.offer(node.next);
}
temp = temp.next;
}
return result.next;
}
}
解题思路:
- 分析题目,合并K个有序的链表,则需要找出这K个链表中最小的那个节点,使用优先队列-二叉堆-最小堆得特性,辅助
- 创建一个虚机头结点的结果链表
- 遍历将K个链表先放进优先队列中,因为是有序的,则第一批放进去的肯定存在最小的节点
- 再一个个出队列,第一个出队的就是最小,将最小的节点放到结果链表中,然后再将最小节点的下一个节点放进优先队列中进行排序
- 最后将