算法---LeetCode 23. 合并K个升序链表

12 篇文章 0 订阅

1. 题目

原题链接

给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表。

示例 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 = [[]]
输出:[]

提示:

k == lists.length
0 <= k <= 10^4
0 <= lists[i].length <= 500
-10^4 <= lists[i][j] <= 10^4
lists[i] 按 升序 排列
lists[i].length 的总和不超过 10^4

Related Topics 堆 链表 分治算法
👍 1068 👎 0

2. 题解

2.1 题解1: 递归分治合并

    /**
     * 解法1 : 递归分治合并
     */
    class Solution {
        public ListNode mergeKLists(ListNode[] lists) {
            return merge(lists, 0, lists.length - 1);
        }

        /**
         * 合并链表数组中 从 下标 start 到 下标 end 的链表
         *
         * @param lists
         * @param start
         * @param end
         * @return
         */
        public ListNode merge(ListNode[] lists, int start, int end) {
            if (start == end) {
                return lists[start];
            }
            // 终止条件
            if (start > end) {
                return null;
            }
            // 分而治之
            int mid = start + (end - start) / 2;
            ListNode h1 = merge(lists, start, mid);
            ListNode h2 = merge(lists, mid + 1, end);
            return mergeTwoList(h1, h2);
        }

        /**
         * 合并两个有序链表
         *
         * @param h1
         * @param h2
         * @return
         */
        public ListNode mergeTwoList(ListNode h1, ListNode h2) {
            ListNode dummy = new ListNode(-1);
            ListNode curr = dummy, p1 = h1, p2 = h2;
            while (p1 != null && p2 != null) {
                if (p1.val <= p2.val) {
                    curr.next = p1;
                    p1 = p1.next;
                } else {
                    curr.next = p2;
                    p2 = p2.next;
                }
                curr = curr.next;

            }

            curr.next = p1 == null ? p2 : p1;
            return dummy.next;
        }
    }

2.2 题解2. 优先队列

    /**
     * 解法2: 优先队列
     */
    class Solution {
        public ListNode mergeKLists(ListNode[] lists) {
            if (lists.length == 0) {
                return null;
            }

            PriorityQueue<ListNode> queue = new PriorityQueue<>(lists.length, new Comparator<ListNode>() {
                @Override
                public int compare(ListNode o1, ListNode o2) {
                    return o1.val - o2.val;
                }
            });

            ListNode dummy = new ListNode(0);
            ListNode p = dummy;
            // 将头结点都加入优先队列
            for (int i = 0; i < lists.length; i++) {
                if (lists[i] != null) {
                    queue.add(lists[i]);
                }
            }

            while (!queue.isEmpty()) {
                p.next = queue.poll();
                p = p.next;
                if (p.next != null) {
                    queue.add(p.next);
                }
            }
            return dummy.next;


        }
    }

2.3 题解3 . 自底向上两两合并迭代

    /**
     * 解法3: 自底向上两两迭代
     */
    class Solution {
        public ListNode mergeKLists(ListNode[] lists) {
            if (lists.length == 0) {
                return null;
            }
            // 外层循环控制步长, 每次合并的结果都保存在 step 下标的位置
            for (int step = 1; step < lists.length; step = step * 2) {
                // 内层循环控制合并, 每次合并两个链表, 合并后的链表头保存在前面的下标位置
                // 由于0乘原因, 只能通过 i 迭代访问后一个链表的下标
                // 合并过程中, 两两合并, 所以下一次合并的链表在 2*step 之后
                for (int i = step; i < lists.length; i += 2 * step) {
                    // 合并的第一个链表的下标为 i-step, 第二个为 i, 结果放入第一个中
                    lists[i - step] = mergeTwoList(lists[i - step], lists[i]);
                    lists[i] = null;
                }
            }
            return lists[0];
        }

        /**
         * 合并两个有序链表
         *
         * @param h1
         * @param h2
         * @return
         */
        public ListNode mergeTwoList(ListNode h1, ListNode h2) {
            ListNode dummy = new ListNode(0);
            ListNode temp = dummy, p1 = h1, p2 = h2;
            while (p1 != null && p2 != null) {
                if (p1.val <= p2.val) {
                    temp.next = p1;
                    p1 = p1.next;
                } else {
                    temp.next = p2;
                    p2 = p2.next;
                }
                temp = temp.next;

            }
            temp.next = p1 == null ? p2 : p1;
            return dummy.next;

        }

    }

参考题解

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值