有序链表合并
有序链表合并(归并排序思想)
题目描述
输入两个递增排序的链表,合并这两个链表并使新链表中的节点仍然是递增排序的。
示例1:
输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4
第一次尝试
- 这道题就是归并排序的变形, 使用两个指针, 分别指向两个链表头部, 每次选取值较小的节点构建新的链表.
- 构建新的链表是生成新的节点还是直接改变节点的指针, 构建新的链表比较耗空间, 所以直接改变节点的指针.
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode head = null;
ListNode current = null;
ListNode p1 = l1;
ListNode p2 = l2;
ListNode tmp = null;
while(p1 != null && p2 != null){
if(p1.val < p2.val){
if(current == null){
current = p1;
tmp = current.next;
current.next = null;
p1 = tmp;
} else {
current.next = p1;
p1 = p1.next;
}
} else{
if(current == null){
current = p2;
tmp = current.next;
current.next = null;
p2 = tmp;
} else{
current.next = p2;
p2 = p2.next;
}
}
if(head == null){
head = current;
}
if(current.next != null){
current = current.next;
}
}
if(p1 != null){
if(current != null){
current.next = p1;
} else{
head = current = p1;
}
}
if(p2 != null){
if(current != null){
current.next = p2;
} else{
head = current = p2;
}
}
return head;
}
改进
上面的代码主要的问题是当current为空时, 必须进行初始化, 并设置头节点, 当current不为空时, 直接设置current.next即可. 为了屏蔽差异, 我们可以引入虚拟的头节点
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode fakeHead = new ListNode(0);
ListNode current = fakeHead;
ListNode p1 = l1;
ListNode p2 = l2;
while (p1 != null && p2 != null){
if(p1.val < p2.val){
current.next = p1;
p1 = p1.next;
current = current.next;
continue;
}
current.next = p2;
p2 = p2.next;
current = current.next;
}
if (p1 != null){
current.next = p1;
}
if (p2 != null){
current.next = p2;
}
return fakeHead.next;
}
收获
- 使用双指针解决归并排序问题
- 在链表操作里面, 往往来说, 要进行节点的初始化, 初始化操作和其他的操作不可合并, 导致出现很多不同的分支, 我们可以试着引入虚拟的节点去屏蔽这种差异.