まず、暴力行為
暴力説明するのはあまりない、私はコード、主に暴力行為2を書き込みません。
- 毎回トップに二つのリストの合併は、その後、新しいリストと他のリストのマージに進みます。これは、n-1回のマージが必要です。
- 一つ一つを比較する方法であり、最初のノードがKのリスト最小から選択して、新しいリンクされたリストに追加するたびに、繰り返し動作。
第二に、プライオリティキュー(小さなスタックの最上位)
実際には、暴力がどのように我々は、リストの最初のノードからKの最小値を選択するか、上記の方法2の変形です。この方法は、小さなパイル上部を作成し、その後、スタックの最上部からの時間を最小限にとることができます。ヒープの最上部は、要素を削除した後の要素を削除後続ノードを表示することがあり、そこには少しヒープの最上部に追加されます。コードは以下の通りであります:
public ListNode mergeKLists(ListNode[] lists) {
if (lists.length == 0)
return null;
if (lists.length == 1)
return lists[0];
//一定要注意新建优先级队列时候,初始化要用的参数
//一个是堆的大小,一个是自定义的比较器
PriorityQueue<ListNode> queue = new PriorityQueue<>(lists.length, new Comparator<ListNode>() {
@Override
public int compare(ListNode o1, ListNode o2) {
if (o1.val < o2.val)
return -1;
else if (o1.val > o2.val)
return 1;
else
return 0;
}
});
//将所有不为null的队列头放到堆中
for (ListNode node : lists) {
if (node != null)
queue.offer(node);
}
ListNode result = new ListNode(-1), p = result;
while (!queue.isEmpty()) { //堆不为空时,不断地取堆顶
ListNode popNode = queue.poll();
p.next = popNode; //将堆顶数据(当前最小的)放到结果后面
p = p.next;
if (popNode.next != null) { //堆顶还有后继,则把后继加入到堆中
queue.offer(popNode.next);
}
}
return result.next;
第三に、合併マージ
常に2つのマージの間、二つのリストをマージしています。
public ListNode mergeKLists(ListNode[] lists) {
if (lists.length == 0)
return null;
if (lists.length == 1)
return lists[0];
int step = 1, index = 0;
//很重要的一步,就是要知道index和step的条件
while (index + step < lists.length) {
for (; index+step < lists.length; index += 2*step) {
//将index和index+step位置的两个链表合并
lists[index] = merge2Lists(lists[index], lists[index+step]);
}
index = 0; //合并一次后,下标从0开始,step乘2
step *= 2;
}
return lists[0];
}
//合并两个有序列表的过程
public ListNode merge2Lists(ListNode list1, ListNode list2) {
ListNode NewHead = new ListNode(0), head = NewHead;
ListNode p1 = list1, p2 = list2;
while (p1 != null && p2 != null) {
if (p1.val <= p2.val) {
head.next = p1;
head = head.next;
p1 = p1.next;
} else {
head.next = p2;
head = head.next;
p2 = p2.next;
}
}
if (p1 != null) {
head.next = p1;
}
if (p2 != null) {
head.next = p2;
}
return NewHead.next;
}