时间:2021-10-17
对于单链表的题目来说,双指针的运用是很广泛的。
合并两个有序链表(Leetcode 21)
题目:将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例:
输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]
思路:
- 由于题目最后需要输出一个新的链表,所以这里需要先新建一个虚拟头结点,以便后续的输出,同时可以避免处理空指针的情况。ListNode dummy = new ListNode(-1);p = dummy;
- 用p1和p2两个指针分别指向l1和l2的头结点,并且比较两个指针的值,值较小的节点链接到p指针
- p指针不断前进,直到p1或者p2走到了链表的末尾,后面就直接将剩下的链接到p指针即可。
代码:
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode dummy = new ListNode(-1);
ListNode p = dummy;
ListNode p1 = l1;
ListNode p2 = l2;
while(p1 != null && p2 != null){
if(p1.val < p2.val){
p.next = p1;
p1 = p1.next;
}
else{
p.next = p2;
p2 = p2.next;
}
p = p.next;
}
if(p1 != null){
p.next = p1;
}
if(p2 != null){
p.next = p2;
}
return dummy.next;
}
}
结果:
注意:
虚拟头结点的使用以及两个指针交替前进的方法。
合并k个有序链表(Leetcode 23)
题目:给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表。
示例:
输入:lists = [[1,4,5],[1,3,4],[2,6]]
输出:[1,1,2,3,4,4,5,6]
解释:链表数组如下:
[
1->4->5,
1->3->4,
2->6
]
将它们合并到一个有序链表中得到。
1->1->2->3->4->4->5->6
思路:
-
方法和上面合并两个有序链表大致上是一样的,取出k个节点的最小值连接到虚拟头节点p上,然后p往后移,直到结束
-
问题:如何快速的得到k个节点的最小值?
这里使用了优先级队列PriorityQueue这种数据结构,把链表节点放到一个最小堆,就可以每次获得
k
个节点中的最小节点。——关于优先级队列在后面的章节补充。 -
后面的思路就和合并两个有序链表一样了。
代码:
import java.util.PriorityQueue;
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
if(lists.length == 0){
return null;
}
ListNode dummy = new ListNode(-1);
ListNode p = dummy;
PriorityQueue<ListNode> pq = new PriorityQueue<>(lists.length, (a,b) -> (a.val-b.val));
for(ListNode head:lists){
if(head != null){
pq.add(head);
}
}
while(!pq.isEmpty()){
ListNode node = pq.poll();
p.next = node;
if(node.next != null){
pq.add(node.next);
}
p = p.next;
}
return dummy.next;
}
}
结果:
注意:
在该题中使用到了一个新的数据结构:优先级队列,同时需要考虑当lists为空的情况。