原题
这是LeetCode上的第21号问题,请看leetcode上的题目描述:
将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例:
输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4
题目意思很清楚,将两个有序链表合并成一个有序链表并返回。
解题思路
涉及到合并的操作,学习过归并排序应该很容易想到使用归并的方法进行合并。如果不了解的话,可以参考下我写的一篇介绍归并排序的文章,了解了归并的思想,解决这道题并不难。
代码实现
注意两个细节
- 是否需要开辟新的内存空间来存放排好序的结点,我使用的方法并没有开辟新的内存空间,因为无论是否开辟,其时间复杂度都是一样的,同为0(n + m),n为l1的结点个数,m为l2的结点个数。不开辟新的内存空间怎么做呢?这里我是直接在l1或者l2的链表上进行操作,如何选择l1或者l2取决于l1和l2的头结点的大小,l1小,则在l1上操作,l2小,则在l2上操作。
- 是否使用虚拟头结点,如果使用的话,就不用判断l1与l2的头结点大小来作为合并后的链表的头结点了。这里我没有使用。
具体的解释见代码中的注释。
class Solution{
public:
ListNode *mergeTwoLists(ListNode *l1, ListNode *l2){
// 处理特殊情况 当l1 == NULL 时, 直接返回l2就好了.
if (!l1) return l2;
// 同理,当l2 == NULL时,直接返回l1就好了,当l1也等于NULL时,返回l1就相当于返回NULL,也没什么问题。
if (!l2) return l1;
// 这里不使用虚拟头结点
ListNode *head;
ListNode *tail;
// 比较L1与l2的大小,确定返回链表的头结点
if (l1->val <= l2->val) {
head = l1;
l1 = l1->next;
} else {
head = l2;
l2 = l2->next;
}
// 使用tail开始进行`合并`的操作
tail = head;
// 往后遍历时,如果l1与l2 都还存在结点,则进行比较结点值得大小,小的则拼接在tail的后面。
while (l1 && l2) {
if (l1->val <= l2->val) {
tail->next = l1;
l1 = l1->next;
} else {
tail->next = l2;
l2 = l2->next;
}
// 拼接完后,结点后移
tail = tail->next;
}
// 在l1 == NULL,或者l2 == NULL 时,拼接剩余的结点。
tail->next = l1 ? l1 :l2;
// 返回头结点
return head;
}
};
如果大家对有些leetcode上的题目有疑问的话,可以参考下我的github:github.com/xiaoswu/Lee…, 上面有一些leetcode上的题目的解答过程。希望能帮到你!