数据结构与算法之深入解析“合并K个升序链表”的求解思路与算法示例
Posted Serendipity·y
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构与算法之深入解析“合并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 <= 104
-
- 0 <= lists[i].length <= 500
-
- -104 <= lists[i][j] <= 104
-
- lists[i] 按升序排列
-
- lists[i].length 的总和不超过 104
二、求解算法
① 顺序合并
- 可以想到一种最朴素的方法:用一个变量 ans 来维护以及合并的链表,第 i 次循环把第 i 个链表和 ans 合并,答案保存到 ans 中。
- C++ 示例:
class Solution
public:
ListNode* mergeTwoLists(ListNode *a, ListNode *b)
if ((!a) || (!b)) return a ? a : b;
ListNode head, *tail = &head, *aPtr = a, *bPtr = b;
while (aPtr && bPtr)
if (aPtr->val < bPtr->val)
tail->next = aPtr; aPtr = aPtr->next;
else
tail->next = bPtr; bPtr = bPtr->next;
tail = tail->next;
tail->next = (aPtr ? aPtr : bPtr);
return head.next;
ListNode* mergeKLists(vector<ListNode*>& lists)
ListNode *ans = nullptr;
for (size_t i = 0; i < lists.size(); ++i)
ans = mergeTwoLists(ans, lists[i]);
return ans;
;
- Java 示例:
class Solution
public ListNode mergeKLists(ListNode[] lists)
ListNode ans = null;
for (int i = 0; i < lists.length; ++i)
ans = mergeTwoLists(ans, lists[i]);
return ans;
public ListNode mergeTwoLists(ListNode a, ListNode b)
if (a == null || b == null)
return a != null ? a : b;
ListNode head = new ListNode(0);
ListNode tail = head, aPtr = a, bPtr = b;
while (aPtr != null && bPtr != null)
if (aPtr.val < bPtr.val)
tail.next = aPtr;
aPtr = aPtr.next;
else
tail.next = bPtr;
bPtr = bPtr.next;
tail = tail.next;
tail.next = (aPtr != null ? aPtr : bPtr);
return head.next;
② 分治合并
- 将 k 个链表配对并将同一对中的链表合并;
- 第一轮合并以后, k 个链表被合并成了 k/2 个链表,平均长度为 2n/k,然后是 k/4 个链表, k/8 个链表等;
- 重复这一过程,直到得到了最终的有序链表。
- C++ 示例:
class Solution
public:
ListNode* mergeTwoLists(ListNode *a, ListNode *b)
if ((!a) || (!b)) return a ? a : b;
ListNode head, *tail = &head, *aPtr = a, *bPtr = b;
while (aPtr && bPtr)
if (aPtr->val < bPtr->val)
tail->next = aPtr; aPtr = aPtr->next;
else
tail->next = bPtr; bPtr = bPtr->next;
tail = tail->next;
tail->next = (aPtr ? aPtr : bPtr);
return head.next;
ListNode* merge(vector <ListNode*> &lists, int l, int r)
if (l == r) return lists[l];
if (l > r) return nullptr;
int mid = (l + r) >> 1;
return mergeTwoLists(merge(lists, l, mid), merge(lists, mid + 1, r));
ListNode* mergeKLists(vector<ListNode*>& lists)
return merge(lists, 0, lists.size() - 1);
;
- Java 示例:
class Solution
public ListNode mergeKLists(ListNode[] lists)
return merge(lists, 0, lists.length - 1);
public ListNode merge(ListNode[] lists, int l, int r)
if (l == r)
return lists[l];
if (l > r)
return null;
int mid = (l + r) >> 1;
return mergeTwoLists(merge(lists, l, mid), merge(lists, mid + 1, r));
public ListNode mergeTwoLists(ListNode a, ListNode b)
if (a == null || b == null)
return a != null ? a : b;
ListNode head = new ListNode(0);
ListNode tail = head, aPtr = a, bPtr = b;
while (aPtr != null && bPtr != null)
if (aPtr.val < bPtr.val)
tail.next = aPtr;
aPtr = aPtr.next;
else
tail.next = bPtr;
bPtr = bPtr.next;
tail = tail.next;
tail.next = (aPtr != null ? aPtr : bPtr);
return head.next;
③ 使用优先队列合并
- 这个方法和前两种方法的思路有所不同,我们需要维护当前每个链表没有被合并的元素的最前面一个,k 个链表就最多有 k 个满足这样条件的元素,每次在这些元素里面选取 val 属性最小的元素合并到答案中。在选取最小元素的时候,我们可以用优先队列来优化这个过程。
- C++ 示例:
class Solution
public:
struct Status
int val;
ListNode *ptr;
bool operator < (const Status &rhs) const
return val > rhs.val;
;
priority_queue <Status> q;
ListNode* mergeKLists(vector<ListNode*>& lists)
for (auto node: lists)
if (node) q.push(node->val, node);
ListNode head, *tail = &head;
while (!q.empty())
auto f = q.top(); q.pop();
tail->next = f.ptr;
tail = tail->next;
if (f.ptr->next) q.push(f.ptr->next->val, f.ptr->next);
return head.next;
;
- Java 示例:
class Solution
class Status implements Comparable<Status>
int val;
ListNode ptr;
Status(int val, ListNode ptr)
this.val = val;
this.ptr = ptr;
public int compareTo(Status status2)
return this.val - status2.val;
PriorityQueue<Status> queue = new PriorityQueue<Status>();
public ListNode mergeKLists(ListNode[] lists)
for (ListNode node: lists)
if (node != null)
queue.offer(new Status(node.val, node));
ListNode head = new ListNode(0);
ListNode tail = head;
while (!queue.isEmpty())
Status f = queue.poll();
tail.next = f.ptr;
tail = tail.next;
if (f.ptr.next != null)
queue.offer(new Status(f.ptr.next.val, f.ptr.next));
return head.next;
以上是关于数据结构与算法之深入解析“合并K个升序链表”的求解思路与算法示例的主要内容,如果未能解决你的问题,请参考以下文章