美文网首页算法
【算法】合并K个排序链表

【算法】合并K个排序链表

作者: 宋唐不送糖 | 来源:发表于2019-11-11 11:03 被阅读0次

    合并K个排序链表

    描述

    合并 k 个排序链表,返回合并后的排序链表。

    输入:
    [
      1->4->5,
      1->3->4,
      2->6
    ]
    输出: 1->1->2->3->4->4->5->6
    

    解题思路

    1.将所有节点添加到数组中,对数组节点从小到大排序,依次取出每个节点串成链表。
       // 时间复杂度:O(n*logn),空间复杂度:O(n)。
       public ListNode mergeKLists(ListNode[] lists) 
        {
            if (lists == null || lists.length == 0) return null;
            
            List<ListNode> nodes = new ArrayList<ListNode>();
            for (ListNode list : lists) {
                while (list != null) {
                    nodes.add(list);
                    list = list.next;
                }
            }
            
            nodes.sort((ListNode node1, ListNode node2) -> {
                return node1.val - node2.val;
            });
            
            ListNode head = new ListNode(0);
            ListNode cur = head;
            for (ListNode node : nodes) {
                cur = cur.next = node;
            }
            return head.next;
        }
    
    2.遍历取出链表数组第一个节点,取最小的节点,然后串起来。
    // 时间复杂度:O(k*n)
    public ListNode mergeKLists(ListNode[] lists) 
        {
            if (lists == null || lists.length == 0) return null;
            
            ListNode head = new ListNode(0);
            ListNode cur = head;
            
            while (true) {
                int minIndex = -1;//记录最小值的索引
                for (int i = 0; i < lists.length; i++) {
                    //某条链表已经取完
                    if (lists[i] == null) continue;
                    //比较小的赋值
                    if (minIndex == -1 || lists[i].val < lists[minIndex].val) {
                        minIndex = i;
                    }
                }
                
                //取出了链表数组所有的值
                if (minIndex == -1) break;
                
                //串起来节点
                cur = cur.next = lists[minIndex];
                //取出后下移
                lists[minIndex] = lists[minIndex].next;
            }
            
            return head.next;
        }
    
    3.利用Java数据结构小顶堆
    // 时间复杂度:O(n*logk),空间复杂度:O(k)。
    public ListNode mergeKLists(ListNode[] lists) 
        {
            if (lists == null || lists.length == 0) return null;
            
            ListNode head = new ListNode(0);
            ListNode cur = head;
            
            PriorityQueue<ListNode> queue = new PriorityQueue<>((ListNode node1, ListNode node2) -> {
                return node1.val - node2.val;
            });
            
            for (ListNode list : lists) {
                if (list == null) continue;
                queue.offer(list);
            }
            
            while (!queue.isEmpty()) {
                ListNode list = queue.poll();
                cur = cur.next = list;
                if (list.next != null) {
                    queue.offer(list.next);
                }
            }
            
            return head.next;
        }
    
    4.分治策略,将链表两两合并成一条,最后第一条链表就是结果。

    合并两条链表
    a、迭代

    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
            if (l1 == null) return l2;
            if (l2 == null) return l1;
            
            //虚拟头结点
            ListNode head;
            
            //赋值头结点
            if (l1.val <= l2.val) {
                head = l1;
                l1 = l1.next;
            } else {
                head = l2;
                l2 = l2.next;
            }
            
            ListNode cur = head;
            //串起来剩余节点
            while (l1 != null && l2 != null) {
                if (l1.val <= l2.val) {
                    cur = cur.next = l1;
                    l1 = l1.next;
                } else {
                    cur = cur.next = l2;
                    l2 = l2.next;
                }
            }
            
            //串完一个链表,剩下的链表直接串后面即可
            if (l1 == null) {
                cur.next = l2;
            } else if (l2 == null) {
                cur.next = l1;
            }
            
            return head;
        }
    

    b、递归

        public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
            if (l1 == null) return l2;
            if (l2 == null) return l1;
            
            if (l1.val <= l2.val) {
                l1.next = mergeTwoLists2(l1.next,l2);
                return l1;
            } else {
                l2.next = mergeTwoLists2(l1,l2.next);
                return l2;
            }
        }
    

    分治代码

    // 时间复杂度:O(n*logk)
    public ListNode mergeKLists(ListNode[] lists) 
        {
            if (lists == null || lists.length == 0) return null;
            
            int step = 1;
            while (step < lists.length) {
                int nextStep = step << 1;// step*2
                            // 相邻2、4、8...
                for (int i = 0; i+step < lists.length; i += nextStep) {
                    lists[i] = mergeTwoLists(lists[i], lists[i+step]);// 合并2条链表
                }
                
                step = nextStep;
            }
            
            return lists[0];
        }
    

    Objective-C版:

    OC版的解法

    相关文章

      网友评论

        本文标题:【算法】合并K个排序链表

        本文链接:https://www.haomeiwen.com/subject/nwozbctx.html