递归法
思路
/**
合并两个排序的链表:
1 → 3 → 5 → 7 → 9 → 12 → 15
2 → 4 → 7 → 15 → 16 → 77
链表的问题可以考虑用递归来做。
而递归问题的话,只需要考虑一层(输入,递归终止条件,操作...->递归,返回值)
*/
递归过程中:
- 输入: 每一次的输入,都是两个有序链表的头节点
- 递归终止条件: 如果一个链表变为空了,那么立即返回另一条链表
- 操作: 使用中间节点保存当前较小的那个节点的值,并进入 递归 去合并(并用
.next
保存递归的返回值) - 返回值:此层调用的递归结束后,将此层的较小节点返回
代码:
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
//-------------在一次递归中----------------
// 输入:两个有序链表的头节点
// 递归终止条件:两个链表中间有一个为空
if(l1 == null) return l2;
if(l2 == null) return l1;
// 操作:找出两个头节点中较小的那一个,将其作为此次的返回结果,并去递归
// 返回结果
ListNode curr= null;
if(l1.val <= l2.val){
curr= l1;
// 需要保存子递归的结果
curr.next = mergeTwoLists(l1.next, l2);
}else{ // l1.val > l2.val
curr= l2;
curr.next = mergeTwoLists(l1, l2.next);
}
// 返回值:子层递归结束后,返回此次的递归结果
return curr;
}
}
迭代法
思路
/**
学习了递归的解法,再来看看迭代的解法。
在递归的解法中,我们用到了一个 curr工作节点,用于保存每一层较小的那个元素
--- 所以我们可以在这里也定义一个工作节点 curr。
递归中通过返回值返回每一次较小的那个节点,上一层中都会有节点接收它
在第一层的递归最终将会得到一个完整的链表
--- 我们通过一个哑节点的方式 dummyNode 存储一个头,并让 curr等于进行拼接链表的操作
*/
代码
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
// 初始化哑节点和工作节点。
// 在链表问题中他们承担了很大的责任
ListNode dummyNode = new ListNode(0);
ListNode curr = dummyNode;
// while循环的终止条件选择很灵活,因此很重要
while(l1!=null && l2!=null){
// curr.next 用于拼接较小的节点
if(l1.val <= l2.val){
curr.next = l1;
l1 = l1.next;
}else{
curr.next = l2;
l2 = l2.next;
}
// 更新工作节点
curr = curr.next;
}
// 退出循环的时候,l1==null 或者 l2==null,或者两者都 ==null
if(l1 == null)
curr.next = l2;
if(l2 == null)
curr.next = l1;
// 哑节点的作用就是这个
return dummyNode.next;
}
}