题目
方法一-迭代(伪头节点)
算法思路
设定一个哨兵结点prehead(伪头节点),便于在最后返回合并后的链表。维护一个prev指针,调整其next指针。重复以下过程直至有一个链表指向了null:
- 若L1当前结点的值小于等于L2,则将L1当前结点接在prev结点的后面,同时将L1指针向后移动一位。
- 否则,将L2当前结点接在prev结点的后面,同时将L2指针向后移动一位。
循环终止时,L1和L2至多有一个非空,由于输入的两个链表均为有序链表,所以直接将非空链表接在合并链表后面即可。
具体代码
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode preHead = new ListNode(-1);//哨兵节点,便于最后返回合并后的链表
ListNode prev = preHead;
while(l1 != null && l2 != null){
//若L1当前节点的值小于L2当前节点值
if(l1.val < l2.val){
prev.next = l1;//将L1当前节点接在prev后面
l1 = l1.next;//L1指针向后移动一位
}else{//若L1当前节点的值大于等于L2当前节点值
prev.next = l2;//将L2当前节点接在prev后面
l2 = l2.next;//L2指针向后移动一位
}
prev = prev.next;
}
//当有一个链表遍历结束时,将另一链表剩余部分直接接到合并链表后面
prev.next = (l1 == null) ? l2 : l1;
return preHead.next;
}
}
复杂度分析
- 时间复杂度:O(m+n),m和n分别为两个链表的长度
- 空间复杂度:O(1)
方法二-递归
算法思路
设
F
(
l
i
s
t
1
,
l
i
s
t
2
)
F(list1, list2)
F(list1,list2) 表示合并有序链表 L1 和 L2,则递推公式为:
F
(
l
i
s
t
1
,
l
i
s
t
2
)
=
{
l
i
s
t
1
[
0
]
+
F
(
l
i
s
t
1
[
1
:
]
,
l
i
s
t
2
)
,
if
l
i
s
t
1
[
0
]
<
l
i
s
t
2
[
0
]
l
i
s
t
2
[
0
]
+
F
(
l
i
s
t
1
,
l
i
s
t
2
[
1
:
]
)
,
if
l
i
s
t
1
[
0
]
≥
l
i
s
t
2
[
0
]
F(list1, list2)= \begin{cases} list1[0]+F(list1[1:], list2),\quad \text{if }list1[0]<list2[0]\\ list2[0]+F(list1,list2[1:]),\quad \text{if }list1[0]\ge list2[0] \end{cases}
F(list1,list2)={list1[0]+F(list1[1:],list2),if list1[0]<list2[0]list2[0]+F(list1,list2[1:]),if list1[0]≥list2[0]
终止条件:两个链表中有一个已经为空
需要考虑边界情况:若其中有链表一开始就为空链,不需要合并
具体代码
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
if(l1 == null || l2 == null){
return l1 == null ? l2 : l1;
}
if(l1.val < l2.val){
l1.next = mergeTwoLists(l1.next, l2);
return l1;
}else{
l2.next = mergeTwoLists(l1, l2.next);
return l2;
}
}
}
复杂度分析
- 时间复杂度:O(m+n),m和n分别为两个链表的长度
- 空间复杂度:O(m+n),m和n分别为两个链表的长度,递归时需要的栈空间大小取决于递归调用的深度,递归函数最多调用m+n次。