如何合并K个升序链表

732 阅读1分钟

做了一张好丑的图

正题

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

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

示例 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个升序链表,可以看做是 合并两个升序链表 的衍生,具体如何实现可以参阅之前的合并两个升序链表的文章。

有了这个基础,这个问题解决起来就容易多了,我们可以有:

方法一:顺序合并两个链表

也可以称之为两两合并,通过数组 pop() 出一个一个链表然后合并,这样就拆解成了 n-1 次的 合并两个升序链表的问题了,这样问题是不是就迎刃而解了?

const mergeTwoLists = (n1, n2) => {

  let res = new ListNode(0) //创建虚拟节点
  let p = res // res 指针
  let p1 = n1 // L1 指针
  let p2 = n2 // L2指针

  while (p1 && p2) {
    if (p1.val < p2.val) {
      p.next = p1 // p指针指向 p1
      p1 = p1.next // L1指针右移
    } else {
      p.next = p2 // p指针指向 p2
      p2 = p2.next // L2指针右移
    }
    p = p.next // p 的指针右移
  }
  p.next = p1 ? p1 : p2 // 当前有一个链表已合并历完, p next 指针直接指向未合并的剩余链表的下一个元素


  return res.next
}


var mergeKLists = function(lists) {
    if (lists.length === 0) {
        return new ListNode(null).next
    }
    let res = lists.pop()
    while(lists.length) {
        const l2 = lists.pop()
        res = mergeTwoLists(res, l2)
    }

    return res
}

以上为顺序合并的代码,也非常好理解。

那么在我们两两合并链表的时候可以发现,是通过指针右移比较大晓得方式进行合并的,同样的,我们可以将此方法用于多个链表的合并,原理相同!

方法二: 多指针右移

ScreenRecorderProject20.gif

如图可知,其实是和两个链表合并原理是一样的,不同的是需要在多个链表中记录下 val 最低的是哪个链表,然后将该链表指针右移,两个链表则直接比较就可以了。

var mergeKLists = function(lists) {
    let res = new ListNode(0)
    let resP = res
    let flag = 0
    lists = lists.filter(item => {
        return item !== null
    })
     while(lists.length > 0) {
        let selectIndex = 0
        let minP = lists[selectIndex]
         for (let index = 1 ; index < lists.length ; index++) {
             if (lists[index].val < minP.val) {
                 minP = lists[index]
                 selectIndex = index
             }
          }
          resP.next = lists[selectIndex]
          resP = resP.next
          lists[selectIndex] = lists[selectIndex].next
          lists = lists.filter(item => {
             return item !== null
          })
     }
     return res.next
};

多个链表的升序合并实际上并不难,只要掌握两个链表的合并,无论是在此基础上叠加(方法一),还是利用相同原理(方法二)都可以很轻松解决,所以基础还是比较重要的。