小根堆-合并k个升序链表

98 阅读1分钟

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
/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode[]} lists
 * @return {ListNode}
 */
var mergeKLists = function(lists) {
  const k = lists.length;
  const heap = new Heap((a, b) => a.val < b.val);
  const result = new ListNode();
  let p = result;
  for (let i = 0; i < k; i++) {
      if(lists[i]) {
        heap.push(lists[i]);
      }
  }

  while (heap.getTop()) {
    const { val, next } = heap.pop();
    if (next) {
      heap.push(next);
    }
    const node = new ListNode(val, null);
    p.next = node;
    p = node;
  }
  return result.next;
};

class Heap {
  constructor(compare) {
    this.nodeList = [];
    this.compare = typeof compare === 'function' ? compare : this.defaultCompare;
  }

  defaultCompare(a, b) {
    return a > b;
  }

  getSize() {
    return this.nodeList.length;
  }
  getTop() {
    if (this.nodeList.length === 0) {
      return null;
    }

    return this.nodeList[0];
  }

  push(value) {
    this.nodeList.push(value);
    this.up(this.nodeList.length - 1);
  }

  up(index) {
    const { compare, parent, nodeList } = this;
    let curIndex = index;
    let parentIndex = parent(curIndex);

    while (curIndex > 0 && compare(nodeList[curIndex], nodeList[parentIndex])) {
      const temp = nodeList[curIndex];
      nodeList[curIndex] = nodeList[parentIndex];
      nodeList[parentIndex] = temp;
      curIndex = parentIndex;
      parentIndex = parent(curIndex);
    }

  }

  parent(index) {
    return index % 2 === 0 ? index / 2 - 1 : (index - 1) / 2;
  }

  pop() {
    if (this.nodeList.length === 0) {
      return null;
    }

    const top = this.nodeList[0];
    this.nodeList[0] = this.nodeList[this.nodeList.length - 1];
    this.nodeList.pop();
    this.down(0);
    return top;
  }

  down(index) {
    const { compare, left, right, nodeList } = this;
    let curIndex = index;
    while (left(curIndex) < nodeList.length) {
      let target = left(curIndex);
      if (right(curIndex) < nodeList.length && compare(nodeList[right(curIndex)], nodeList[left(curIndex)])) {
        target = right(curIndex);
      }

      if (compare(nodeList[curIndex], nodeList[target])) {
        break;
      }

      const temp = nodeList[curIndex];
      nodeList[curIndex] = nodeList[target];
      nodeList[target] = temp;
      curIndex = target;
    }
  }

  left(index) {
    return index * 2 + 1;
  }

  right(index) {
    return index * 2 + 2;
  } 

}