算法修炼之路——【链表】Leetcode 23 合并K个有序链表

题目描述

合并K个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。

示例1:

输入: lists = {listA, listB, listC}, listA= [1, 4, 5], listB = [1, 3, 4], listC = [2, 6]
输出: [1, 1, 2, 3, 4, 4, 5, 6]

思路分析

这道题目为困难难度,这道题和多路归并排序方法思路很像,核心思想是分而治之。我们在Leetcode21已知如何对两个排序链表进行合并,这里K个有序链表可通过两两合并的方式进行排序,这里我们给出示意图:
在这里插入图片描述
图1
如图1所示,我们在第一次两两排序时,间隔为1:{0,1; 2,3};第二次两两排序时,间隔为3:{0,3},易推断,间隔interval初始值应为1,之后更新为2 * interval, interval = interval*2.

这里我们还需要注意,当输入的链表矩阵长度为奇数时,最后一项会在最终结果的前一次两两排序时参与到运算中。

解题步骤

  1. 初始化间隔整型变量interval,并求取输入矩阵长度len
  2. 遍历链表矩阵,并在每次遍历后更新一对排序链表中的下表较小的链表指针,同时更新interval = 2*interval
  3. 返回链表矩阵的首元素lists[0]

解题代码

    public static ListNode solution(ListNode[] lists) {
        if(lists == null) return null;
        if(lists.length == 1) return lists[0];
        
        /* Step1: Init  */
        int interval = 1;       
        int len = lists.length;
        
        /* Step2: go through the head-list
        and
        compare joint listnode in array-lists
         */        
        for (int i = 0; i < len; i = i + interval*2) {
            for(int j = 0; j < len-interval; j=j+interval){
                lists[j] = sortTwoSortedList(lists[j], lists[j + interval]);
            }
            interval *= 2;                        
        }

        return lists[0];

    }

    private static ListNode sortTwoSortedList(ListNode listA, ListNode listB) {
        if (listA == null) {
            return listB;
        }
        if (listB == null) {
            return listA;
        }

        /* Step1: Init. pointers */
        ListNode dummyHead = new ListNode(0);
        ListNode pA = listA;
        ListNode pB = listB;
        ListNode tmpTail = dummyHead;

        /* Step2: go through the head-list
        and
        compare pA.next.val and pB.val
         */
        while (pA != null && pB != null) {
            if (pA.val < pB.val) {
                tmpTail.next = pA;
                pA = pA.next;
            } else {
                tmpTail.next = pB;
                pB = pB.next;
            }
            tmpTail = tmpTail.next;
        }

        // Step3: connect subsequent if exists
        tmpTail.next = pA == null ? pB : pA;
        /* Step4: return  */
        return dummyHead.next;
    }

复杂度分析

已知链表矩阵的长度分别为k(即链表个数),链表长度可设为N

时间复杂度:代码中我们存在for循环的嵌套,且两两交换的时间复杂度为O(N);我们对链表矩阵进行了分治解法(第一层for循环时间复杂度为O(logk)),故时间复杂度即为O(Nlogk);
空间复杂度:我们这里没有设置辅助容器,故空间复杂度为O(1).

GitHub源码

完整可运行文件请访问GitHub

发布了47 篇原创文章 · 获赞 55 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/u011106767/article/details/105595471
今日推荐