Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。
题目描述
-
给你一个链表数组,每个链表都已经按升序排列。
-
请你将所有链表合并到一个升序链表中,返回合并后的链表。
示例 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 = []
输出: []
输入:lists = [[]]
输出:[]
思路分析
- 根据题目知道链表数组内的链表都是有序的,如果 链表数组长度为 我们可能会想出用小根堆来维护 个链表的下标,在每次取出其中一个最小值链表的 后都会自动调节。此时我们需要同时维护 个链表,好像有有一点复杂,不妨多想想还有其他方法吗?
- 既然是有序链表数组,我们可以带着分治的思想来思考。发现可以把链表数组不断分割,链表数组为 1 或 0 时就可以归并了,因为我们分割成了许许多多的小链表数组,形成了多路自底向上的归并。如下图(图源网络)。
AC 代码
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
int n = lists.length;
if (n == 0) return null;
return merge(lists, 0, n - 1);
}
private ListNode merge(ListNode[] lists, int left, int right) {
if (left == right) return lists[left];
int mid = left + (right - left) / 2;
ListNode leftList = merge(lists, left, mid);
ListNode rightList = merge(lists, mid + 1, right);
ListNode tempList = new ListNode();
ListNode head = tempList;
while (leftList != null && rightList != null) {
if (leftList.val <= rightList.val) {
tempList.next = new ListNode(leftList.val);
tempList = tempList.next;
leftList = leftList.next;
} else {
tempList.next = new ListNode(rightList.val);
tempList = tempList.next;
rightList = rightList.next;
}
}
if (leftList != null) {
tempList.next = leftList;
}
if (rightList != null) {
tempList.next = rightList;
}
return head.next;
}
}
总结
- 这也是一道 leetcode 上 hard 难度的题目,仔细分析后发现也没有我们想的那么难了,只要在细节上处理好了,遇到的问题也就不再是问题了!