主题
方法一:迭代(尾插法)
前置知识
思路
创建一个哨兵节点,作为合并后的新链表头节点的前一个节点。这样可以避免单独处理头节点,也无需特判链表为空的情况,从而简化代码。
比较
重复上述过程,直到其中一个链表为空。
循环结束后,其中一个链表可能还有剩余的节点,将剩余部分加到新链表的末尾。
最后,返回新链表的头节点,即哨兵节点的下一个节点。
python
class Solution:
def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]:
cur = dummy = ListNode() # 用哨兵节点简化代码逻辑
while list1 and list2:
if list1.val < list2.val:
cur.next = list1 # 把 list1 加到新链表中
list1 = list1.next
else: # 注:相等的情况加哪个节点都是可以的
cur.next = list2 # 把 list2 加到新链表中
list2 = list2.next
cur = cur.next
cur.next = list1 or list2 # 拼接剩余链表
return dummy.nextcpp
// C++ 版待补充cpp
class Solution {
public:
ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
ListNode dummy; // 用哨兵节点简化代码逻辑
ListNode* cur = &dummy; // cur 指向新链表的末尾
while (list1 && list2) {
if (list1->val < list2->val) {
cur->next = list1; // 把 list1 加到新链表中
list1 = list1->next;
} else { // 注:相等的情况加哪个节点都是可以的
cur->next = list2; // 把 list2 加到新链表中
list2 = list2->next;
}
cur = cur->next;
}
cur->next = list1 ? list1 : list2; // 拼接剩余链表
return dummy.next;
}
};复杂度分析
- 时间复杂度:
,其中 为 的长度, 为 的长度。 - 空间复杂度:
。仅用到若干额外变量。
方法二:递归(头插法)
前置知识
如何理解递归?计算机是怎么执行递归的?【基础算法精讲 09】
思路
直接把 mergeTwoLists 当作递归函数:
- 递归边界:如果其中一个链表为空,直接返回另一个链表作为合并后的结果。
- 如果两个链表都不为空,则比较两个链表当前节点的值,选择较小的节点插在前面。
- 如果
的节点值更小,那么取出 ,递归调用 mergeTwoLists(list1.next, list2),拿到递归返回的链表,把插在前面。 - 如果
的节点值更小,那么取出 ,递归调用 mergeTwoLists(list1, list2.next),拿到递归返回的链表,把插在前面。
- 如果
python
class Solution:
def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]:
if list1 is None: return list2 # 注:如果都为空则返回空
if list2 is None: return list1
if list1.val < list2.val:
list1.next = self.mergeTwoLists(list1.next, list2)
return list1
list2.next = self.mergeTwoLists(list1, list2.next)
return list2cpp
// C++ 版待补充cpp
class Solution {
public:
ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
if (list1 == nullptr) return list2; // 注:如果都为空则返回空
if (list2 == nullptr) return list1;
if (list1->val < list2->val) {
list1->next = mergeTwoLists(list1->next, list2);
return list1;
}
list2->next = mergeTwoLists(list1, list2->next);
return list2;
}
};复杂度分析
- 时间复杂度:
,其中 为 的长度, 为 的长度。 - 空间复杂度:
。递归需要 的栈空间。
思考题
如果只保留两个有序链表中的相同元素(求交集),要怎么做?注意,如果第一个链表有
欢迎在评论区发表你的思路/代码。
分类题单
- 滑动窗口与双指针(定长/不定长/单序列/双序列/三指针/分组循环)
- 二分算法(二分答案/最小化最大值/最大化最小值/第K小)
- 单调栈(基础/矩形面积/贡献法/最小字典序)
- 网格图(DFS/BFS/综合应用)
- 位运算(基础/性质/拆位/试填/恒等式/思维)
- 图论算法(DFS/BFS/拓扑排序/基环树/最短路/最小生成树/网络流)
- 动态规划(入门/背包/划分/状态机/区间/状压/数位/数据结构优化/树形/博弈/概率期望)
- 常用数据结构(前缀和/差分/栈/队列/堆/字典树/并查集/树状数组/线段树)
- 数学算法(数论/组合/概率期望/博弈/计算几何/随机算法)
- 贪心与思维(基本贪心策略/反悔/区间/字典序/数学/思维/脑筋急转弯/构造)
- 链表、树与回溯(前后指针/快慢指针/DFS/BFS/直径/LCA)
- 字符串(KMP/Z函数/Manacher/字符串哈希/AC自动机/后缀数组/子序列自动机)
欢迎关注 B站@灵茶山艾府