23. 合并K个排序链表

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

示例:

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

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

 

这道题有三种解法,

1,逐个合并队列,队列1+队列2=sum1,sum1+队列3,=sum2,。。。直到合并完毕,这种算法效率最低,为O(nk*k)

2,使用优先队列,

    把n个队列的头加入一个优先队列,每次取出第一个元素e,肯定是当前最小的元素,
    取出后,如果e.next!=null,把e.next加入队列中,
    直到队列为空,合并完毕

   复杂度为:O(kn×logk)。

 

3,把队列两两合并,然后对合并后的结果进行两两合并,直到和为一个,复杂度为: O(kn \times \log k)O(kn×logk)

详细解释,见leetcode官方

https://leetcode-cn.com/problems/merge-k-sorted-lists/solution/he-bing-kge-pai-xu-lian-biao-by-leetcode-solutio-2/

 

代码如下:实现了1,和2,


public class Solution15 {

	public static void main(String[] args) {
		Solution15 so3 = new Solution15();

		int[][] inits = new int[][] { { 1, 2, 2 }, { 1, 1, 2 } };
		ListNode[] lists = so3.getInitList(inits);
		ListNode node = so3.mergeKLists(lists);
		do {
			System.out.print(node.val + ",");
			node = node.next;
		} while (node != null);
		System.out.println();

		lists = so3.getInitList(inits);
		node = so3.mergeKLists2(lists);
		do {
			System.out.print(node.val + ",");
			node = node.next;
		} while (node != null);

	}

	/**
	 * 常规算法,逐个比对,插入每个队列
	 * 
	 * @param lists
	 * @return
	 */
	public ListNode mergeKLists(ListNode[] lists) {
		if (lists == null || lists.length == 0) {
			return null;
		}
		if (lists.length == 1) {
			return lists[0];
		}
		ListNode head = lists[0];
		int headi = 0;
		// 计算head的val
		for (int i = 0; i < lists.length; i++) {
			if (lists[i] == null) {
				continue;
			}
			if (head == null) {
				head = lists[i];
				headi = i;
			}
			if (head.val > lists[i].val) {
				lists[headi] = head;
				head = lists[i];
				headi = i;
			}
		}
		lists[headi] = null;
		ListNode n = head;
		ListNode nx = null;
		for (int i = 0; i < lists.length; i++) {
			ListNode n2 = lists[i];
			if (n2 == null) {
				continue;
			}
			// 从头开始合并
			n = head;
			while (n.next != null && n2 != null) {
				// 如果n2,比n小,说明需要排在n前面
				if (n.next.val > n2.val) {
					nx = n.next;
					n.next = n2;
					n2 = n2.next;
					n.next.next = nx;
				} else {
					n = n.next;// 说明主队列太大,需要往后移动
				}
			}
			if (n2 != null) {// 如果最后n2不为空,把n2加到队尾
				n.next = n2;
			}
		}
		return head;
	}

	/**
	 * 把n个队列的头加入一个优先队列,每次取出第一个元素e,肯定是当前最小的元素,
	 * 取出后,如果e.next!=null,把e.next加入队列中,
	 * 直到队列为空,合并完毕
	 * 
	 * @param lists
	 * @return
	 */
	public ListNode mergeKLists2(ListNode[] lists) {
		if (lists == null || lists.length == 0) {
			return null;
		}
		if (lists.length == 1) {
			return lists[0];
		}
		Queue<ListNode> pqe = new PriorityQueue<ListNode>(new Comparator<ListNode>() {
			@Override
			public int compare(ListNode o1, ListNode o2) {
				if (o1 == null) {// 空最大,放后面
					return 1;
				}
				if (o2 == null) {
					return -1;
				}
				if (o1.val > o2.val) {
					return 1;// 前面的大
				}
				return -1;
			}
		});

		for (int i = 0; i < lists.length; i++) {
			if (lists[i] != null) {
				pqe.add(lists[i]);
			}
		}

		ListNode nx = null;
		ListNode head = pqe.poll();
		if (head == null) {
			return null;
		}
		if (head.next != null) {
			pqe.add(head.next);
		}
		boolean hasMore = true;// 判断是否还有更多的数据需要加入队列
		nx = pqe.poll();
		ListNode n = head;
		while (nx != null) {
			n.next = nx;
			n = n.next;
			if (nx.next != null) {
				pqe.add(nx.next);
			}
			nx = pqe.poll();
		}

		return head;
	}

	ListNode[] getInitList(int[][] towIs) {
		ListNode[] nodes = new ListNode[towIs.length];
		for (int j = 0; j < towIs.length; j++) {
			int[] ones = towIs[j];
			if (ones == null || ones.length == 0) {
				continue;
			}
			ListNode n = new ListNode(ones[0]);
			nodes[j] = n;
			for (int i = 1; i < ones.length; i++) {
				n.next = new ListNode(ones[i]);
				n = n.next;
			}
		}

		return nodes;

	}
}

 

 

 

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页