「这是我参与2022首次更文挑战的第9天,活动详情查看:2022首次更文挑战」。
题目:给定两个有序链表,要求将两个有序链表进行合并,输出合并后的链表(保持有序)。
解题思路
本题的简单思路很容易想到,因为两个链表都是有序的,此时我们可以使用双指针法来解决问题,具体思路为:首先设置一个头节点,用来保存最终的合并链表,之后为了减少内存使用,此处将原链表的头结点作为两个待移动指针,通过循环来遍历两个链表,每次遍历判断两个链表指针指向的值的大小,哪个小则设置头节点的next为此节点,之后此节点后移,头节点也后移,直到两个链表存在一个链表为空时,停止循环。之后判断哪个链表为空,将头节点的next指向不为空的链表即可,代码如下:
public static ListNode mergeTwoLists(ListNode list1, ListNode list2) {
ListNode head = new ListNode(0);
ListNode cur = head;
while(list1!=null && list2!=null){
if(list1.val<list2.val){
cur.next = list1;
list1 = list1.next;
}else {
cur.next = list2;
list2 = list2.next;
}
cur = cur.next;
}
cur.next = list1==null?list2:list1;
return head.next;
}
该算法的时间复杂度为,其中m,n分别表示两个链表的长度,空间复杂度为。
进阶解法 递归
递归的思路很巧妙,使用递归,此处必须引入递归的两个条件,第一个是终止条件,第二个是函数的执行体(函数干了什么)。根据本题,如果使用递归解决问题,那么终止条件即为两个链表其中一个链表为空则返回另一个链表,函数体则是判断两个链表的第一个元素的大小,哪个链表元素小则设置哪个链表的next指针指向下一层递归函数,直到递归结束。实际上,此递归可以想象为每次拿出元素较小的结点,根据多次循环,链表结点离散化,之后递归结束是系统出栈将元素串起来了,代码如下:
public static ListNode mergeTwoLists2(ListNode list1, ListNode list2){
if(list1 == null) return list2;
if(list2 == null) return list1;
if(list1.val < list2.val){
list1.next = mergeTwoLists2(list1.next, list2);
return list1;
}else {
list2.next = mergeTwoLists2(list1, list2.next);
return list2;
}
}
因为算法递归调用最多会调用合并后链表长度的次数,因此该算法的时间复杂度为, 而每次调用的结果都存在系统栈空间中,因此空间复杂度为。