23.LeetCode困难合并K个升序链表

201 阅读2分钟

「这是我参与2022首次更文挑战的第1天,活动详情查看:2022首次更文挑战」。

一、 题目

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

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

示例 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 = [[]] 输出:[]

二、 解析

链表的定义

首先,要实现链表,我们先搞懂一些链表的基本东西,因为这很重要!

链表是一组节点组成的集合,每个节点都使用一个对象的引用来指向它的后一个节点。指向另一节点的引用讲做链。下面我画了一个简单的链接结构图,方便大家理解。

image.png

    1. 节点中左侧储存val数据,右侧next储存下一个链表节点的引用地址
    1. 有上面的储备知识,我们总体的思路就是把链表转成数组,通过Array中的sort排序,然后再把数组转成Array

三、 解题

解题方法一: 用for循环的方法去拆链表->转数组->再组装成链表

/**
 * 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) {
    let res = new ListNode() // 最后要返回的链表
    let control = res
    let arr = [] // 中间排序用的数组
    // 1. 转数组
    lists.forEach( (v,i) => {
        while(1) {
            if(v) {
                arr[arr.length ] = v.val
                v = v.next
            } else {
                break
            }
        }
    })
    // 2. 数组没数据就返回
    if(arr.length === 0) return null
    // 排序
    arr.sort((a,b) => a-b)
    // 3. 再组装成链表返回
    arr.forEach((v,i) => {
        control.next = new ListNode(v);
        control = control.next;
    })
    return res.next
}

这种方法执行效率高

image.png

解题方法二:用递归的方法去拆链表->转数组->再组装成链表

/**
 * @param {ListNode[]} lists
 * @return {ListNode}
 */
var mergeKLists = function(lists) {
    let arr = []
    lists.forEach(v => flatArr(v,arr))
    arr.sort((a,b) => a -b)
    if(arr.length == 0) return null
    let newListNode = new ListNode(arr[0])
    arrToList(arr,newListNode)
    return newListNode
}


var flatArr =  function (listNode,arr) {
     if(listNode) {
        arr.push(listNode.val)
        if(listNode.next) {
            flatArr(listNode.next,arr)
        }
     }
}

var arrToList = function arrToList(arr,listNode) {
    arr.forEach((v,i) => {
        if(i != 0) {
            let node = new ListNode(v)
            mountedLastNode(listNode, node)
        }
    })
}

var mountedLastNode = function (listNode,lastNode) {
    if(!listNode.next) {
        listNode.next = lastNode
    } else {
       mountedLastNode(listNode.next,lastNode)
    }
}

image.png

这个方法效率不高主要在于,最后把排好序的数组转成链表的时候,每次调mountedLastNode方法都去遍历了一次链表,重复了,但也是思路的一种,后期再优化下。

四、思考

虽然链表数据结构在实际开发业务中并不是太常用,但在react hooks源码中有用到,在一定的场景,链表的效率会比数组快,前端了解下这种数据结构还是必要的。