合并两个有序链表
难度:
标签:
题目描述
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例 1:
输入:l1 = [1,2,4], l2 = [1,3,4] 输出:[1,1,2,3,4,4]
示例 2:
输入:l1 = [], l2 = [] 输出:[]
示例 3:
输入:l1 = [], l2 = [0] 输出:[0]
提示:
- 两个链表的节点数目范围是
[0, 50]
-100 <= Node.val <= 100
l1
和l2
均按 非递减顺序 排列
代码结果
运行时间: 48 ms, 内存: 17 MB
/*
* 思路:
* 1. 将链表转换为流,合并并排序。
* 2. 将排序后的数据重新构造成链表。
*/
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
// 将两个链表转换为列表
List<Integer> list1 = new ArrayList<>();
List<Integer> list2 = new ArrayList<>();
while (l1 != null) {
list1.add(l1.val);
l1 = l1.next;
}
while (l2 != null) {
list2.add(l2.val);
l2 = l2.next;
}
// 合并两个列表并排序
List<Integer> sortedList = Stream.concat(list1.stream(), list2.stream())
.sorted()
.collect(Collectors.toList());
// 将排序后的列表重新构造成链表
ListNode dummy = new ListNode(0);
ListNode current = dummy;
for (int val : sortedList) {
current.next = new ListNode(val);
current = current.next;
}
return dummy.next;
}
}
解释
方法:
该题解使用了双指针的方法来合并两个有序链表。具体思路如下:
1. 创建一个虚拟头节点 dummy,使用指针 p 指向 dummy。
2. 同时遍历两个链表 list1 和 list2,比较当前节点的值,将较小的节点接到 p 指针后面。
3. 移动对应链表的指针到下一个节点。
4. 移动 p 指针到新接入的节点。
5. 重复步骤 2-4,直到其中一个链表遍历完毕。
6. 将剩余未遍历完的链表接到 p 指针后面。
7. 返回 dummy 的下一个节点,即合并后的链表的头节点。
时间复杂度:
O(m+n)
空间复杂度:
O(1)
代码细节讲解
🦆
为什么在处理剩余未遍历完的链表时,你选择直接创建新的ListNode而不是直接将剩余链表接在p指针后面?
▷🦆
在对两个链表的节点值进行比较时,当值相等时选择将哪个链表的节点接到新链表后面有什么依据?
▷🦆
这种双指针方法处理合并两个有序链表时,如果链表长度差异很大,是否会影响算法的效率?
▷🦆
在创建虚拟头节点 dummy 的目的是什么?在不使用虚拟头节点的情况下,这个算法应如何修改?
▷🦆
题解中提到的空间复杂度是O(1),但是在合并过程中创建了新的ListNode实例。这是否意味着对原链表结构的修改?如果想保持原有链表结构不变,应该如何处理?
▷🦆
返回的是 dummy 的下一个节点,这种处理方式是否有可能在某些情况下导致错误或是异常,例如当输入的两个链表都为空时?
▷相关问题
合并 K 个升序链表
给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表。
示例 1:
输入:lists = [[1,4,5],[1,3,4],[2,6]] 输出:[1,1,2,3,4,4,5,6] 解释:链表数组如下: [ 1->4->5, 1->3->4, 2->6 ] 将它们合并到一个有序链表中得到。 1->1->2->3->4->4->5->6
示例 2:
输入:lists = [] 输出:[]
示例 3:
输入:lists = [[]] 输出:[]
提示:
k == lists.length
0 <= k <= 10^4
0 <= lists[i].length <= 500
-10^4 <= lists[i][j] <= 10^4
lists[i]
按 升序 排列lists[i].length
的总和不超过10^4
合并两个有序数组
给你两个按 非递减顺序 排列的整数数组 nums1
和 nums2
,另有两个整数 m
和 n
,分别表示 nums1
和 nums2
中的元素数目。
请你 合并 nums2
到 nums1
中,使合并后的数组同样按 非递减顺序 排列。
注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1
中。为了应对这种情况,nums1
的初始长度为 m + n
,其中前 m
个元素表示应合并的元素,后 n
个元素为 0
,应忽略。nums2
的长度为 n
。
示例 1:
输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3 输出:[1,2,2,3,5,6] 解释:需要合并 [1,2,3] 和 [2,5,6] 。 合并结果是 [1,2,2,3,5,6] ,其中斜体加粗标注的为 nums1 中的元素。
示例 2:
输入:nums1 = [1], m = 1, nums2 = [], n = 0 输出:[1] 解释:需要合并 [1] 和 [] 。 合并结果是 [1] 。
示例 3:
输入:nums1 = [0], m = 0, nums2 = [1], n = 1 输出:[1] 解释:需要合并的数组是 [] 和 [1] 。 合并结果是 [1] 。 注意,因为 m = 0 ,所以 nums1 中没有元素。nums1 中仅存的 0 仅仅是为了确保合并结果可以顺利存放到 nums1 中。
提示:
nums1.length == m + n
nums2.length == n
0 <= m, n <= 200
1 <= m + n <= 200
-109 <= nums1[i], nums2[j] <= 109
进阶:你可以设计实现一个时间复杂度为 O(m + n)
的算法解决此问题吗?