Leetcode刷题23. 合并K个升序链表

给你一个链表数组,每个链表都已经按升序排列。

请你将所有链表合并到一个升序链表中,返回合并后的链表。

示例 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

来源:力扣(LeetCode
链接:https://leetcode.cn/problems/merge-k-sorted-lists/
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

感谢labuladong单链表的六大解题套路,你都见过么?王尼玛四种解法+多图演示 23. 合并K个排序链表

class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
//		return mergeKListsI(lists);
//		return mergeKListsII(lists);
//		return mergeKListsIII(lists);
		return mergeKListsIV(lists);
	}

	//方法四:类似于四数之和,将大问题转换为熟悉的小问题
	//时间复杂度O(n*k^2),空间复杂度O(logk)
	//四数之和:https://blog.csdn.net/Bonbon_wen/article/details/111501252
	private ListNode mergeKListsIV(ListNode[] lists) {
		if (lists == null || lists.length == 0) {
			return null;
		}
		int k = lists.length;
		if (k == 1) {
			return lists[0];
		}
		return mergeHelper(lists, 0, k);
	}

	private ListNode mergeHelper(ListNode[] lists, int start, int k) {
		int len = lists.length;
		ListNode res = null;
		if (k == 2) {
			return mergeTwoList(lists[start], lists[len - 1]);
		}
		for (int i = start; i < len - (k - 1); i++) {
			ListNode sub = mergeHelper(lists, start + 1, k - 1);
			res = mergeTwoList(lists[start], sub);
		}
		return res;
	}

	//方法三:利用二叉堆,将链表头节点放入一个最小堆中,每次获取k个节点中最小节点
	//时间复杂度O(n*logk),空间复杂度O(k)
	private ListNode mergeKListsIII(ListNode[] lists) {
		if (lists == null || lists.length == 0) {
			return null;
		}
		ListNode dummy = new ListNode(-1);
		ListNode p = dummy;
		PriorityQueue<ListNode> pq = new PriorityQueue<>(lists.length, (a, b) -> a.val - b.val);
		//将 k 个链表的头结点加入最小堆
		for (ListNode head : lists) {
			if (head != null) {
				pq.offer(head);
			}
		}
		while (!pq.isEmpty()) {
			//获取最小节点,添加到结果链表中
			ListNode node = pq.poll();
			p.next = node;
			if (node.next != null) {
				pq.offer(node.next);
			}
			//p 指针不断前进
			p = p.next;
		}
		return dummy.next;
	}

	//方法二:分治算法,两两合并
	//将数组一分为二,然后再拆分,直到规模为1不能再拆分时便返回,之后再两两合并。然后不断重复这个合并过程,直到最终得到一个有序的链表。
	//时间复杂度O(n*logk),空间复杂度O(logk)
	private ListNode mergeKListsII(ListNode[] lists) {
		if (lists == null || lists.length == 0) {
			return null;
		}
		return mergeLists(lists, 0, lists.length - 1);
	}

	private ListNode mergeLists(ListNode[] lists, int start, int end) {
        if (start > end) {
			return null;
		}
		if (start == end) {
			return lists[start];
		}
		//通过mid将数组一分为二,并不断缩小规模,当规模为1时返回并开始合并
		int mid = start + (end - start) / 2;
		ListNode left = mergeLists(lists, start, mid);
		ListNode right = mergeLists(lists, mid + 1, end);
		//通过合并两个链表,不断增大其规模,整体看就是不断缩小 --> 最后不断扩大的过程
		return mergeTwoList(left, right);
	}

	//方法一:逐一合并两条链表
	//利用第21题思想,用一个变量ans来维护合并的链表,循环调用两两合并链表的方法
	//时间复杂度O(n*k^2),空间复杂度O(1)
	private ListNode mergeKListsI(ListNode[] lists) {
		if (lists == null || lists.length == 0) {
			return null;
		}
		ListNode ans = null;
		for (ListNode list : lists) {
			ans = mergeTwoList(ans, list);
		}
		return ans;
	}

	private ListNode mergeTwoList(ListNode l1, ListNode l2) {
		ListNode dummy = new ListNode(-1);
		ListNode prev = dummy;
		while (l1 != null && l2 != null) {
			if (l1.val <= l2.val) {
				prev.next = l1;
				l1 = l1.next;
			} else {
				prev.next = l2;
				l2 = l2.next;
			}
			prev = prev.next;
		}
		if (l1 == null) {
			prev.next = l2;
		}
		if (l2 == null) {
			prev.next = l1;
		}
		return dummy.next;
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值