写这个主要是为了记录自己学习的情况,题有哪些好的解法,用到什么样的知识点,整理一下思绪。
原文链接:https://www.cnblogs.com/HelloXHD/p/12815142.html
题目
题目链接
这题是简单难度的,两个链表已经是有序状态,思路比较简单。
题解
迭代法
1.设置一个哨兵结点(假结点)pHead,用于作为返回最终结果链表的头指针;
2.设置一个游标p,随着链表结点的增加移动,初始情况下,p指向pHead;
3.在l1、l2均未达到链表结尾(null)前提下循环迭代。
l1当前指向结点的值小于等于l2当前指向结点的值时,p.next指向l1,l1移向下个结点,否则,p.next指向l2,l2移向下个结点;游标p移向下个结点。
4.由于当循环结束时,l1、l2中有一个仍然非空,所以直接将剩余结点添加。
初始状态;
第一次循环;
第二次循环;(以此类推)
最后一次循环,l1先达到结尾(null);
最后将剩余结点全部添加至p.next;
Java源码:
class Solution2 {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode pHead = new ListNode(-1);//哨兵结点
ListNode p = pHead;//游标
while(l1 != null && l2 != null){
if (l1.val <= l2.val){
p.next = l1;
l1 = l1.next;
p = p.next;
}else{
p.next = l2;
l2 = l2.next;
p = p.next;
}
}
p.next = l1 == null ? l2 : l1;//添加剩余结点
return pHead.next;//返回时跳过头结点
}
}
算法复杂度:
时间复杂度:O(N+M),N和M分别为两个有序链表的长度,循环次数不会超过两个长度之和,其他操作的时间复杂度都是常数级别的;
空间复杂度:O(1),只需要常数的空间存放若干个变量。
递归法
这个我没有想到,看了题解后才知道这个解法!
官方题解中有这样的思路:
1.首先,递归终止的条件是l1或l2为空(null);
2.如果l1.val < l2.val的话,表头就是l1的头结点,否则是l2的头结点;
3.递归的内容是得到的两个链表中小的结点后,在剩下的结点中找下一个小的结点;
Java源码:
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
if (l1 == null){
return l2;
}
else if (l2 == null){
return l1;
}
else if (l1.val < l2.val){
l1.next = mergeTwoLists(l1.next, l2);
return l1;
} else{
l2.next = mergeTwoLists(l1, l2.next);
return l2;
}
}
}
算法复杂度:
时间复杂度:O(n+m),其中 n 和 m 分别为两个链表的长度。因为每次调用递归都会去掉 l1 或者 l2 的头节点(直到至少有一个链表为空),函数 mergeTwoList 至多只会递归调用每个节点一次。因此,时间复杂度取决于合并后的链表长度,即 O(n+m)。
空间复杂度:O(n+m),递归就是程序内部维护了一个栈,每次将最小值压栈,也就是用一个栈来维护顺序。
总结
两种方法虽然时间复杂度一样,但在我实际试验中,递归法效率比迭代法高。