问题:
在O(N lgK) 时间内合并K个有序链表, 这里N指的是K个链表中所有的元素个数。
分析:
这是一道非常经典的面试题,在很多大公司的面试题中,此题频繁出现。这题也是算法导论的作业题。
这题的思路如下:
1) 在每一个链表中取出第一个值,然后把它们放在一个大小为K的数组里,然后把这个数组当成heap,然后把该堆建成最小堆。此步骤的时间复杂度为O(K)
2 )取出堆中的最小值(也是数组的第一个值),然后把该最小值所处的链表的下一个值放在数组的第一个位置。如果链表中有一个已经为空(元素已经都被取出),则改变heap的大小。然后,执行MIN-HEAPIFY操作,此步骤的时间复杂度为O(lg K).
3 ) 不断的重复步骤二,直到所有的链表都为空。
代码如下:
- public void minHeapify(Node[] node, int index, int size) {
- int left = 2 * index + 1;
- int right = 2 * index + 2;
- int smallest;
- if (left < size && node[left].data < node[index].data) {
- smallest = left;
- } else {
- smallest = index;
- }
- if (right < size && node[right].data < node[smallest].data) {
- smallest = right;
- }
- if (smallest != index) {
- exchange(node, smallest, index);
- minHeapify(node, smallest, size);
- }
- }
- public void buildMinHeap(Node[] node, int size) {
- for (int i = size / 2 - 1; i >= 0; i--) {
- minHeapify(node, i, size);
- }
- }
- public Node mergeKSortedList(Node[] heads) {
- Node head = null; // the head of the merged list
- Node current = null;
- int size = heads.length;
- Node[] heap = new Node[heads.length]; // create a heap
- // initialize the value of the heap
- for (int i = 0; i < heads.length; i++) {
- heap[i] = heads[i];
- heads[i] = heads[i].next;
- }
- // create a min heap
- buildMinHeap(heap, size);
- int tempSize = size;
- while (size > 0) {
- if (head == null) {
- head = heap[0];
- current = head;
- } else {
- current.next = heap[0];
- current = current.next;
- }
- if (heap[0].next == null) {
- size--;
- } else {
- heap[0] = heap[0].next;
- }
- // if the size of heap changes, we need to move all the elements in the heap to
- // the front of the heap
- if (size != tempSize) {
- for (int i = 0; i < size; i++) {
- heap[i] = heap[i+1];
- }
- tempSize = size;
- }
- minHeapify(heap, 0, size);
- }
- return head;
- }