题目描述
给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表。
示例 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 = [[]]
输出:[]
通过的代码
我的代码(采用vector,进行比较大小):
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* mergeKLists(vector<ListNode*>& lists) {
ListNode*root=new ListNode(-1);
root->next=NULL;
ListNode*node;
ListNode*lastNode=root;
int flag;
while(!lists.empty())
{
flag=-1;
node=new ListNode(1000);
for(int i=0;i<lists.size();i++)
{
if(lists[i]==NULL)
{
continue;
}
if(lists[i]->val<node->val)
{
node=lists[i];
flag=i;
}
}
if(node->val==1000)
break;
lastNode->next=node;
lastNode=node;
lists[flag]=node->next;
}
lastNode->next=NULL;
return root->next;
}
};
最优代码(优先队列):
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
struct cmp{
bool operator()(ListNode*a,ListNode*b)
{
return a->val>b->val;
}
};
class Solution {
public:
ListNode* mergeKLists(vector<ListNode*>& lists) {
priority_queue<ListNode*,vector<ListNode*>,cmp>queue;
for(int i=0;i<lists.size();i++)
{
if(lists[i]!=NULL)
queue.push(lists[i]);
}
if(queue.empty())
return NULL;
ListNode*root=new ListNode(-1);
ListNode*node;
ListNode*lastNode=root;
while(!queue.empty())
{
node=queue.top();
queue.pop();
lastNode->next=node;
lastNode=lastNode->next;
if(node->next)
queue.push(node->next);
}
lastNode->next=NULL;
return root->next;
}
};
解题思路
这个题目最好的办法是用优先队列priority_queue。因为我们每次要找到所有链表中最小的元素,并且将其作为最后返回的链表的当前元素。所以这里有一个排序是很关键的。排序这里我们可以想到很多办法,单单使用vector我们就可以实现排序,并且很容易可以写出来。但是C++中有一个优先队列是专门用来解决这类寻找最小值,最大值的问题的,所以使用优先队列是最好的。
使用优先队列的思想就是,每次将top队首结点作为当前结点加入到合并后的链表中。并且每次在添加一个结点后就要删除队首结点并且将队首结点的下一个结点push到优先队列queue中(如果下一个结点已经是NULL就不用push了)。一直循环,直到queue为空,此时所有结点都已经合并到新链表中。
这里需要注意的第一点,优先队列在自定义排序规则的时候,我们定义的排序结构体是cmp,但是最后排序采用的是!cmp,意思是cmp定义成从小到大排序的时候,最后出来的实则是从大到小排序。第二点是,刚开始在初始化优先队列的时候,就要把一些空的给排除掉,不能将空的链表存储在优先队列中,这样后面才好操作。
知识点补充
优先队列我之前不太了解。查了查资料才知道,其实使用起来和队列queue是类似的,push是压入元素,top是得到队首元素,empty是检查队列是否为空。但是也有不同的地方,比如pop是删除队首元素(因为队首是最大或者最小的,是我们要操作的,删除队首最符合我们的需求)。