LeetCode 21. 合并两个有序链表(易)& 剑指offer 面试题25. 合并两个排序的链表(易)
链表结合迭代思想解决该问题
题目
将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
测试用例
功能测试(输入的两个链表有多个节点;节点的值互不相同或者存在值相等的多个节点)。 特殊测试(两个链表的一个或者两个头节点为 nullptr
指针;两个链表中只有一个节点)。
本题考点
考查应聘者分析问题的能力。解决这个问题需要大量的指针操作,应聘者如果没有透彻地分析问题形成清晰的思路,则很难写出正确的代码。 考查应聘者能不能写出鲁棒的代码。由于有大量指针操作,应聘者如果稍有不慎就会在代码中遗留很多与鲁棒性相关的隐患。建议应聘者在写代码之前全面分析哪些情况会引入空指针,并考虑清楚怎么处理这些空指针。
示例
示例1
1 |
|
考察知识点
链表、递归、迭代
核心思想
Python Trick
将传入的链表转化成list,相加排序之后再转换回去,注意做特判。
递归
我们可以如下递归地定义在两个链表里的 merge 操作(忽略边界情况,比如空链表等):
\(\left\{ \begin{array}{ll} list1[0] + merge(list1[1:], list2) & list1[0] < list2[0] \\ list2[0] + merge(list1, list2[1:]) & otherwise \end{array} \right.\)
也就是说,两个链表头部较小的一个与剩下元素的 merge
操作结果合并。
我们直接将以上递归过程建模,首先考虑边界情况。
1、特殊的,如果 \(l1\) 或者 \(l2\) 一开始就是 \(None\) ,那么没有任何操作需要合并,所以我们只需要返回非空链表。
2、否则,我们要判断 \(l1\) 和 \(l2\) 哪一个的头元素更小,然后递归地决定下一个添加到结果里的值。
3、如果两个链表都是空的,那么过程终止,所以递归过程最终一定会终止。
迭代
我们可以用迭代的方法来实现。我们假设 \(l1\) 元素严格比 \(l2\)元素少,我们可以将 \(l2\) 中的元素逐一插入 \(l1\) 中正确的位置。
算法
1、首先,我们设定一个哨兵节点 "prehead" ,这可以在最后让我们比较容易地返回合并后的链表。
2、我们维护一个 prev
指针,我们需要做的是调整它的 next
指针。然后,我们重复以下过程,直到 l1
或者 l2
指向了 None
:
2.1、如果 l1
当前位置的值小于等于 l2
,我们就把 l1
的值接在 prev
节点的后面同时将 l1
指针往后移一个。
2.2、 否则,我们对 l2
做同样的操作。
2.3、不管我们将哪一个元素接在了后面,我们都把 prev
向后移一个元素。
3、在循环终止的时候, l1
和 l2
至多有一个是非空的。由于输入的两个链表都是有序的,所以不管哪个链表是非空的,它包含的所有元素都比前面已经合并链表中的所有元素都要大。这意味着我们只需要简单地将非空链表接在合并链表的后面,并返回合并链表。
Python版本
方法一的实现
1 |
|
时间复杂度 \(O(n)\)
执行用时 :48 ms, 在所有 Python3 提交中击败了29.79%的用户
内存消耗 :13.6 MB, 在所有 Python3 提交中击败了40.52%的用户
递归的实现
1 |
|
时间复杂度:\(O(n + m)\)。 因为每次调用递归都会去掉 \(l1\) 或者 \(l2\) 的头元素(直到至少有一个链表为空),函数 mergeTwoList
中只会遍历每个元素一次。所以,时间复杂度与合并后的链表长度为线性关系。 空间复杂度:\(O(n + m)\)。调用 mergeTwoLists
退出时 \(l1\) 和 \(l2\) 中每个元素都一定已经被遍历过了,所以 \(n + m\)个栈帧会消耗 \(O(n + m)\)的空间。
执行用时 :36 ms, 在所有 Python3 提交中击败了85.48%的用户
内存消耗 :13.3 MB, 在所有 Python3 提交中击败了41.12%的用户
迭代的实现 推荐
1 |
|
时间复杂度:\(O(n + m)\)。因为每次循环迭代中,l1
和 l2
只有一个元素会被放进合并链表中, while 循环的次数等于两个链表的总长度。所有其他工作都是常数级别的,所以总的时间复杂度是线性的。
空间复杂度:\(O(1)\) 。迭代的过程只会产生几个指针,所以它所需要的空间是常数级别的。
执行用时 :40 ms, 在所有 Python3 提交中击败了66.60%的用户
内存消耗 :13.5 MB, 在所有 Python3 提交中击败了41.03%的用户
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!