合并K个升序链表20201225

0. 题目

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

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

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

1. 优先队列

1.1 分析

优先队列的主要思路:

  • 利用优先队列的特性,把链表数组中所有的链表节点逐个放入优先队列;
  • 然后逐个从优先队列poll出来,优先队列最小的最先出来;

1.2 代码 6ms 40.2mb

public ListNode mergeKLists(ListNode[] lists) {
	if (lists == null || lists.length == 0) return null;
	
	PriorityQueue<ListNode> queue = new PriorityQueue<>(new Comparator<ListNode>() {
		public int compare(ListNode o1, ListNode o2) {
			return o1.val - o2.val;
		}
	});
	for (ListNode nodes : lists) {
		while (nodes != null) {
			queue.add(nodes);
			nodes = nodes.next;
		}
	}
	
	ListNode pre = new ListNode(0);
	ListNode cur = pre;
	while (!queue.isEmpty()) {
		cur.next = queue.poll();
		cur = cur.next;
	}
	
	cur.next = null;
	return pre.next;
}

2. 优化的优先队列

2.1 分析

优化后的主要思路:

  • 因为链表已经是升序的,所以最小的节点肯定从k个链表的头结点里面选;
  • 优先队列节点个数可以始终保持是k个节点;

2.2 代码 5ms 40.2mb

public ListNode mergeKLists2(ListNode[] lists) {
	if (lists == null || lists.length == 0) return null;
	
	PriorityQueue<ListNode> queue = new PriorityQueue<>(new Comparator<ListNode>() {
		public int compare(ListNode o1, ListNode o2) {
			return o1.val - o2.val;
		}
	});
	for (ListNode nodes : lists) {
		if (nodes != null) {
			queue.add(nodes);
		}
	}
	
	ListNode pre = new ListNode(0);
	ListNode cur = pre;
	while (!queue.isEmpty()) {
		ListNode temp = queue.poll();
		cur.next = temp;
		cur = cur.next;
		if (temp.next != null) {
			queue.add(temp.next);
		}
	}
	
	cur.next = null;
	return pre.next;
}

3. 两两合并

3.1 分析

主要思路:

  • 采用分而治之的思想两两合并,最后合成一个链表;
  • 链表数组从中间开始分割,直到两个链表为最小单元开始合并;
  • 然后逐步合并已经被合并的链表

备注:此处也可以采用第一个链表与第二个链表合并,之后与第三个链表合并,之后与第四个链表合并,直到最后;这种运行时间较长达到200多毫秒。

3.2 代码 3ms 40.9MB

public ListNode mergeKLists3 (ListNode[] lists) {
if (lists == null | lists.length == 0) return null;
	return merge(lists, 0, lists.length-1);
}

ListNode merge(ListNode[] lists, int begin, int end) {
	if (begin == end) return lists[begin];
	int middle = begin + (end - begin)/2;
	ListNode left = merge(lists, begin, middle);
	ListNode right = merge(lists, middle+1, end);
	return mergeTwoList(left, right);
}

// 两个链表合并
ListNode mergeTwoList(ListNode l1, ListNode l2) {
	if (l1 == null || l2 == null) {
		return l1 == null ? l2 : l1;
	}
	if (l1.val <= l2.val) {
		l1.next = mergeTwoList(l1.next, l2);
		return l1;
	} else {
		l2.next = mergeTwoList(l1, l2.next);
		return l2;
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值