023 合并K个排序链表

7人阅读 评论(0) 收藏 举报
分类:

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];
    }
查看评论

[各种面试题] 合并k个排序链表

思路是用一个优先队列,给它自定义一个排序函数即可。 /*链表结点的定义(请不要在代码中定义该类型) struct ListNode { int val; ListNode *next; ...
  • a83610312
  • a83610312
  • 2013-09-19 13:13:31
  • 1330

LintCode-分治-合并k个排序链表

合并k个排序链表 合并k个排序链表,并且返回合并后的排序链表。尝试分析和描述其复杂度。 样例 给出3个排序链表[2->4->null,null,-1->null],返回 -1->2->4->null...
  • lz1997
  • lz1997
  • 2017-09-28 16:22:08
  • 180

lintcode-合并k个排序链表-104

合并k个排序链表,并且返回合并后的排序链表。尝试分析和描述其复杂度。 样例 给出3个排序链表[2->4->null,null,-1->null],返回 -1->2->4->null /** ...
  • ljlstart
  • ljlstart
  • 2015-10-19 21:20:51
  • 815

合并k个增序链表

合并k个增序链表问题归并排序是一个比较简单的算法,特别是二路归并排序,且用数组存储各个数列时。修改索引只需要简单的++操作即可。但是如果换成链表,将二路换成多路,对链表操作接触不多的还是值得注意练习下...
  • junbujianwpl
  • junbujianwpl
  • 2016-12-15 20:50:05
  • 255

用最小堆将k个已排序链表合并为一个排序链表

问题:请给出一个时间为O(nlgk),用来将k个已排序链表合并为一个排序链表的算法。此处的n为所有输入链表中元素的总数。 编程思路: 假设k个链表都是非降序排列的。 (1)取k个元素建立最小堆,...
  • ywk253100
  • ywk253100
  • 2014-04-02 16:36:19
  • 1062

合并两个排序的链表[剑指offer]之python实现

题目描述输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。题目链接开辟新的链表空间:# -*- coding:utf-8 -*- # class ListNo...
  • huaxixidongbeishida
  • huaxixidongbeishida
  • 2016-10-24 21:14:04
  • 1094

leetcode解题之23.Merge k Sorted Lists Java版本(合并k个有序的链表)

leetcode解题之23.Merge k Sorted Lists Java版本(合并k个有序的链表)
  • mine_song
  • mine_song
  • 2017-04-07 10:32:55
  • 1109

LeetCodet题解--23. Merge k Sorted Lists(合并K个已排序的链表)

链接 LeetCode题目:https://leetcode.com/problems/generate-parentheses GitHub代码:https://github.com/...
  • gatieme
  • gatieme
  • 2016-04-08 16:32:28
  • 1735

经典算法——合并K个有序链表

一、题目要求: 将K个有序链表合并为一个有序链表 二、实现方法: 方法一:利用最小堆方法 用一个大小为K的最小堆(用优先队列+自定义降序实现)(优先队列就是大顶堆,队头元素最大,自定义为降序后,就...
  • geekmanong
  • geekmanong
  • 2016-06-01 21:46:57
  • 6291
    个人资料
    专栏达人 持之以恒
    等级:
    访问量: 4911
    积分: 517
    排名: 9万+
    博客专栏
    最新评论