LeetCode(C++)刷题计划:21-合并两个有序链表
21-合并两个有序链表
@Author:CSU张扬
@Email:csuzhangyang@gmail.com or csuzhangyang@qq.com
Category | Difficulty | Pass rate | Tags | Companies |
---|---|---|---|---|
algorithms | Easy | 57.92% | linked-list | amazon / apple / linkedin / microsoft |
1. 题目
将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例:
输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/merge-two-sorted-lists/
2. 解法
2.1 解法一:归并排序
- 创建一个新的链表
h
,用于存储合并后的链表。 - 遍历两个链表。比较两者当前的
val
大小,小的则加入到h
中,并向后移,另外一个链表不用移动。直至某一个链表遍历到尾部,结束。 - 此时肯定有一个链表没有遍历到尾部,将这个链表剩余的元素依次加入到
h
后面即可。
执行用时: 8 ms, 在所有 cpp 提交中击败了96.15%的用户
内存消耗: 9.1 MB, 在所有 cpp 提交中击败了73.70%的用户
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
ListNode* h = new ListNode(0);
ListNode* head = h;
while(l1 && l2) {
if (l1->val < l2->val) {
h->next = new ListNode(l1->val);
h = h->next;
l1 = l1->next;
} else {
h->next = new ListNode(l2->val);
h = h->next;
l2 = l2->next;
}
}
if (l1) {
while(l1) {
h->next = new ListNode(l1->val);
h = h->next;
l1 = l1->next;
}
} else if (l2) {
while(l2) {
h->next = new ListNode(l2->val);
h = h->next;
l2 = l2->next;
}
}
ListNode* ptrDelete = head;
head = head->next;
delete ptrDelete;
return head;
}
};
2.2 解法二:递归(两种)
2.2.1 简单递归
- 递归思路:
我们每次从两个链表的头结点选出一个较小的放在结果中,并在原链表中删除该结点,然后继续比较两个链表。直至一个链表为空。 - 递归结束条件:
当某个链表为空时,递归结束,但我们返回的是另一个链表。因为另一个链表剩下的肯定是值最大的那部分。例如:if(l1 == nullptr) { return l2; }
。
执行用时: 12 ms, 在所有 cpp 提交中击败了69.38%的用户
内存消耗: 9 MB, 在所有 cpp 提交中击败了74.60%的用户
class Solution {
public:
ListNode *mergeTwoLists(ListNode *l1, ListNode *l2) {
if(l1 == nullptr){
return l2;
}
if(l2 == nullptr){
return l1;
}
if(l1->val <= l2->val){
l1->next = mergeTwoLists(l1->next, l2);
return l1;
}
else{
l2->next = mergeTwoLists(l1, l2->next);
return l2;
}
}
};
2.2.2 利用swap函数递归
swap函数介绍:
swap(a, b)
:交换a和b。在此结构体中的意思就是 a->next
和 b->next
交换,a->val
和 b->val
也交换。
- 首先注意,我们的合并后的链表是
a
头结点所指向的链表,也就是a
所走过的位置, 都被按顺序加了进来。 - 总的思想就是:若
a->val > b->val
,就swap(a, b)
,把a
放到小的那个节点。
反之,a
继续向所在节点后面移动,继续比较,a
会始终保持在较小的那个节点上。 - 若
a
所在链表到达尾部时(a = nullptr
),说明另外一个链表剩余的都是最大的几个值,我们这时仍需要swap(a, b)
,将a
放到另一个链表剩余的值上。 - 后续我会画个图例出来。
执行用时 :8 ms, 在所有 cpp 提交中击败了95.91%的用户
内存消耗 :8.7 MB, 在所有 cpp 提交中击败了97.11%的用户
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* mergeTwoLists(ListNode* a, ListNode* b) {
if (!a || b && a->val > b->val) swap(a, b);
if (a) a->next = mergeTwoLists(a->next, b);
return a;
}
};