LeetCode 第二十三题 合并K个排序链表
合并 k 个排序链表,返回合并后的排序链表。尝试分析和描述算法的复杂度。
示例:
输入:
[
1->4->5,
1->3->4,
2->6
]
输出: 1->1->2->3->4->4->5->6
本次方法研究参考了网址中所介绍的方法。总共讨论了五种方法。
方法一
将K个链表的所有节点值放入到一个数组中,然后对数组进行排序,再构建一个新的链表,将其返回。
python
class ListNode(object):
def __init__(self, x):
self.val = x
self.next = None
class Solution(object):
def mergeKLists(self, lists):
nodes = []
head = point = ListNode(0)
for node in lists:
while node:
nodes.append(node.val)
node = node.next
nodes = sorted(nodes)
for x in nodes:
point.next = ListNode(x)
point = point.next
return head.next
Java
public class ListNode {
int val;
ListNode next = null;
ListNode(int x) {
val = x;
}
}
public ListNode mergeKLists(ListNode[] lists) {
ListNode result = new ListNode(0);
ListNode point = result;
List<Integer> list = new ArrayList<Integer>();
for (ListNode node : lists) {
while (node != null) {
list.add(node.val);
node = node.next;
}
}
Collections.sort(list);
for (int x : list) {
point.next = new ListNode(x);
point = point.next;
}
return result.next;
}
C++
struct ListNode
{
int val;
ListNode* next;
ListNode(int x):val(x),next(NULL) {}
};
class Solution
{
public:
ListNode* mergeKLists(vector<ListNode*>&lists)
{
ListNode* result = new ListNode(0);
ListNode* point = result;
list<int> l = list<int>();
for(int i=0; i<lists.size(); i++)
{
while(lists[i])
{
l.push_back(lists[i]->val);
lists[i]=lists[i]->next;
}
}
l.sort();
for(list<int>::iterator it = l.begin(); it!=l.end(); it++)
{
point->next=new ListNode(*it);
point=point->next;
}
return result->next;
}
};
方法二
找寻出K个链表中的最小节点,并将其从K个链表集中剔除,再将其添加到新的链表中,直到K个链表都为空为止。
Java
public ListNode mergeKLists(ListNode[] lists) {
ListNode result = new ListNode(0);
ListNode point = result;
while (true) {
int min_val = Integer.MAX_VALUE;
int position = -1;
for (int i = 0; i < lists.length; i++) {
if (lists[i] != null) {
if (lists[i].val < min_val) {
min_val = lists[i].val;
position = i;
}
}
}
if (min_val == Integer.MAX_VALUE) {
break;
}
point.next = new ListNode(min_val);
point = point.next;
lists[position] = lists[position].next;
}
return result.next;
}
C++
ListNode* mergeKLists(vector<ListNode*>&lists)
{
ListNode* result = new ListNode(0);
ListNode* point = result;
while(true)
{
int min_val = INT_MAX;
int position = -1;
for(int i=0;i<lists.size();i++)
{
if(lists[i]!=NULL)
{
if(lists[i]->val<min_val)
{
min_val = lists[i]->val;
position = i;
}
}
}
if(min_val==INT_MAX)
break;
point->next = new ListNode(min_val);
point = point->next;
lists[position] = lists[position]->next;
}
return result->next;
}
python
测试用例131个,通过130个,最后一个超时。
def mergeKLists(self, lists):
head = point = ListNode(0)
while True:
min_val, position = sys.maxsize, -1
for i in range(len(lists)):
if lists[i] and lists[i].val < min_val:
min_val = lists[i].val
position = i
if min_val == sys.maxsize:
break;
point.next = ListNode(min_val)
point = point.next
lists[position] = lists[position].next
return head.next
方法三
本方法和方法一类似,主要不同点在于使用了一个优先队列。
因为使用了优先队列,比较对象为ListNode,也就是我们自己定义的类,无论是在Java,c++还是python中,都需要为优先队列指定特殊的比较函数。当然,Python可以在其中添加元组,不必指定比较函数,但在实际操作中,在LeetCode提交的代码,是可以通过的,但是在我的电脑上操作时,无法比较,最终只好为其指定了比较函数。
Python
from Queue import PriorityQueue
class ListNode(object):
def __init__(self, x):
self.val = x
self.next = None
def __lt__(self, other):
return self.val < other.val
class Solution(object):
def mergeKLists(self, lists):
head = point = ListNode(0)
q = PriorityQueue()
for l in lists:
if l:
q.put(l)
while not q.empty():
node = q.get()
point.next = ListNode(node.val)
point = point.next
node = node.next
if node:
q.put(node)
return head.next
Java
public ListNode mergeKLists(ListNode[] lists){
ListNode result = new ListNode(0);
ListNode point = result;
PriorityQueue<ListNode> q = new PriorityQueue<>(valComparator);
for(ListNode node:lists){
if(node!=null){
q.add(node);
}
}
while(!q.isEmpty()){
ListNode current_node = q.poll();
point.next = new ListNode(current_node.val);
point = point.next;
current_node = current_node.next;
if(current_node!=null){
q.add(current_node);
}
}
return result.next;
}
private static Comparator<ListNode> valComparator = new Comparator<ListNode>() {
@Override
public int compare(ListNode o1, ListNode o2) {
return (int)(o1.val - o2.val);
}
};
C++
class myCompare
{
public:
bool operator()(ListNode* node_1,ListNode* node_2)const
{
return node_1->val>node_2->val;
}
};
class Solution
{
public:
ListNode* mergeKLists(vector<ListNode*>&lists)
{
ListNode* head = new ListNode(0);
ListNode* point = head;
priority_queue<ListNode*,vector<ListNode*>,myCompare>q;
for(int i=0;i<lists.size();i++)
{
if(lists[i]!=NULL)
q.push(lists[i]);
}
while(!q.empty())
{
ListNode* current_node=q.top();
q.pop();
point->next=new ListNode(current_node->val);
point=point->next;
current_node=current_node->next;
if(current_node!=NULL)
q.push(current_node);
}
return head->next;
}
};
方法四
本次题目是“合并K个排序链表”,其实我们可以从题目合并两个有序链表中获得灵感,将K个链表两两合并(merge lists onr by one),得到最终结果。
python
有一个测试用例未通过(超时),有待改进。
def mergeKLists(self, lists):
head = point = ListNode(0)
for node in lists:
point.next = self.mergeTwoLists(point.next, node)
return head.next
def mergeTwoLists(self, l1, l2):
if not l1:
return l2
if not l2:
return l1
if l1.val < l2.val:
l1.next = self.mergeTwoLists(l1.next, l2)
return l1
else:
l2.next = self.mergeTwoLists(l1, l2.next)
return l2
C++
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2)
{
if(l1==NULL)return l2;
if(l2==NULL)return l1;
if(l1->val<l2->val)
{
l1->next=mergeTwoLists(l1->next,l2);
return l1;
}
else
{
l2->next=mergeTwoLists(l1,l2->next);
return l2;
}
}
ListNode* mergeKLists(vector<ListNode*>&lists)
{
ListNode* head = new ListNode(0);
ListNode* point = head;
for(int i=0; i<lists.size(); i++)
point->next=mergeTwoLists(point->next,lists[i]);
return head->next;
}
Java
private ListNode mergeTwoLists(ListNode l1, ListNode l2){
if(l1==null)return l2;
if(l2==null)return l1;
if(l1.val<l2.val){
l1.next=mergeTwoLists(l1.next, l2);
return l1;
}else{
l2.next=mergeTwoLists(l1, l2.next);
return l2;
}
}
public ListNode mergeKLists(ListNode[] lists){
ListNode head = new ListNode(0);
ListNode point = head;
for(ListNode node:lists){
point.next=mergeTwoLists(point.next, node);
}
return head.next;
}
方法五
和方法四类似,将K个链表分成两两一组,使用方法:合并两个有序链表,将其合并,再将结果两两分组,合并,直到得到最终结果。
Java
class Solution {
private ListNode mergeTwoLists(ListNode l1, ListNode l2){
if(l1==null)return l2;
if(l2==null)return l1;
if(l1.val<l2.val){
l1.next=mergeTwoLists(l1.next, l2);
return l1;
}else{
l2.next=mergeTwoLists(l1, l2.next);
return l2;
}
}
public ListNode mergeKLists(ListNode[] lists) {
if(lists==null||lists.length==0)return null;
int length = lists.length;
int interval = 1;
while (interval < length) {
for (int i = 0; i < length - interval; i += interval * 2) {
lists[i] = mergeTwoLists(lists[i], lists[i + interval]);
}
interval *= 2;
}
return lists[0];
}
}
Python
def mergeTwoLists(self, l1, l2):
if not l1:
return l2
if not l2:
return l1
if l1.val < l2.val:
l1.next = self.mergeTwoLists(l1.next, l2)
return l1
else:
l2.next = self.mergeTwoLists(l1, l2.next)
return l2
def mergeKLists(self, lists):
length = len(lists)
interval = 1
while interval < length:
for i in range(0, length - interval, interval * 2):
lists[i] = self.mergeTwoLists(lists[i], lists[i + interval])
interval *= 2
return lists[0] if length > 0 else lists
C++
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2)
{
if(l1==NULL)return l2;
if(l2==NULL)return l1;
if(l1->val<l2->val)
{
l1->next=mergeTwoLists(l1->next,l2);
return l1;
}
else
{
l2->next=mergeTwoLists(l1,l2->next);
return l2;
}
}
ListNode* mergeKLists(vector<ListNode*>&lists)
{
if(lists.size()==0)return NULL;
int length=lists.size();
int interval=1;
while(interval<length)
{
for(int i=0; i<length-interval; i+=interval*2)
{
lists[i]=mergeTwoLists(lists[i],lists[i+interval]);
}
interval*=2;
}
return lists[0];
}