题记
转眼已过去很多年了,登录园子看到几年前自己记录的笔记,感慨万千,庆幸的是自己还在这行没有放弃,不过,随着工作经验的积累,感觉自己越来越无知,索性最近又捡起9年前刚毕业工作那会儿无知的劲儿,来刷题换换脑子~~~
题目描述
该题来自LeetCode第21题:合并两个有序链表
https://leetcode-cn.com/problems/merge-two-sorted-lists/
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例:
输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]
解题思路
- 创建一个虚拟头节点,其下一个节点为从L1, L2的头节点中选取值较小的节点,假设合并完成,则返回辅助节点的下一个节点,即为最终链表的头节点;
- 新建一个辅助节点,比较L1, L2当前节点的值,其下一个节点也指向L1, L2中值较小的节点,向后移动较小值的节点,同时辅助节点也后移一位;
- 重复第2步,直至L1, L2其中一个链表遍历完成, 辅助节点的下一个节点指向剩下未遍历完成的链表即可。
总结下来,其实就像是拿着一个针(辅助节点)穿珠子,比较两串珠子头上一颗珠子的大小,把小的穿上(辅助节点的下一个节点指向二者小的节点),重复该动作,到其中一串珠子穿完,剩下的无需比较直接穿到后面即可。
通过文字描述还是比较抽象,通过画图的形式来演示每一步,相对来说,就比较好理解了,我按照上述步骤画了一下推演图,如下:
- compare比较链表头节点大小
- pre下一个节点指向值小的链表
- 较小的链表头向后移动一位
- pre也向后移动一位(指向合并后的链表尾节点)
Java代码实现
public class MergeTwoLists {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
if (l1 == null) return l2;
if (l2 == null) return l1;
// 虚拟头节点,下一个节点指向L1,L2二者中较小的头节点
ListNode preHead = new ListNode(-1);
// 辅助节点引用
ListNode pre = preHead;
while (l1 != null && l2 != null) {
// 辅助节点的下一个节点为值小的节点
// 较小值的节点向后移动
if (l1.val > l2.val) {
pre.next = l2;
l2 = l2.next;
} else {
pre.next = l1;
l1 = l1.next;
}
// 辅助节点也同步向后移动
pre = pre.next;
}
// 如果其中一个链表已经结束,则剩下节点接到后面即可
pre.next = l1 == null ? l2 : l1;
// 返回虚拟头节点的下一个节点
return preHead.next;
}
}
总结
该解法的时间复杂度为O(m+n), m、n分别为链表L1、L2的长度;空间复杂度为 O(1), 引入了辅助节点,没有利用其它额外的空间。另外,还有另外一种解法是递归,俗话说,递归是一看就会,一写就跪,等有空了再试试。