前言
本文是LC第21题:合并两个有序链表
题目描述
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
提示:
两个链表的节点数目范围是 [0, 50]
-100 <= Node.val <= 100
l1 和 l2 均按 非递减顺序 排列
示例1
输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]
示例 2:
输入:l1 = [], l2 = []
输出:[]
示例 3:
输入:l1 = [], l2 = [0]
输出:[0]
解题思路
一个链表的代表就是头结点,要合并两个有序链表,只要找到value值较小的头结点,后面的节点按顺序挂在头结点上即可。先来实现一下返回较小的头结点,
if (l1.value < l2.value) {
return l1;
} else {
return l2;
}
当一个链表当前节点为null时,说明链表已经迭代结束了,这时应该返回另一个链表的当前节点,这样就有了边界条件:
if (l1 == null) {
return l2;
} else if (l2 == null) {
return l1;
}
有了最小的节点,还要将两个链表分别递归向前,然后把递归的结果挂在较小节点的next上:
if (l1.value < l2.value) {
l1.next = merge2ListNode(l1.next, l2);
return l1;
} else {
l2.next = merge2ListNode(l1, l2.next);
return l2;
}
代码
递归解法
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
if ( ! l1 || l2 && l1->val > l2->val ) swap ( l1, l2 );
if ( l1 ) l1->next = mergeTwoLists ( l1->next, l2 );
return l1;
}
};
非递归解法
先分享一下最容易想到的思路。
新建一个链表newHead,不断的比较输入的两个有序链表中的最小值,不断以最小值建立新结点,插入到新链表newHead上。
该方法的时间复杂度是O(m+n),其中m、n分别为输入的两个链表的长度。
该方法的空间复杂度是O(m+n),需要重建m+n个链表节点。
那有没有空间复杂度为O(1),时间复杂度为O(m+n)的方法呢?
答案当然是有。
该方法和思路一很相似,只不过不新建链表结点,而是把输入的两个结点串起来。
具体是怎么操作呢?
首先设置一个pre指针,指向一个新建的结点,它是我们找到输出结果的关键。
接下来设立一个end指针,指向我们结果链表(pre)的最后一个元素,用来从两条输入链表中串联新的元素。
然后,遍历两个链表,每次找到较小的结点,将该结点插入结果链表(pre),插入的方法是把结点接到end指针后面。
完成上述工作后,需要更新输入链表的头指针和end指针,一切就大功告成啦。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
ListNode* dummyNode = new ListNode(-1);
ListNode* tail = dummyNode;
while(l1 || l2)
{
/*第一条if的逻辑解释*//*目的是保证 l1 始终指向tail接下来要链接的那个较小节点*/
/*
如果 l1 为空, 代表 l2 非空, 因此,直接 swap
如果 l1 非空, 如果 l2 为空, l1 就是目标节点
如果 l2 非空, l1->val > l2->val 时, swap
*/
if(!l1 || l2 && l1->val > l2->val) swap(l1, l2);
if(l1) tail = tail->next = l1, l1 = l1->next;
}
ListNode* head = dummyNode->next;
delete dummyNode;
return head;
}
};