首页 > 其他分享 >23. 合并 K 个升序链表(难)

23. 合并 K 个升序链表(难)

时间:2025-01-10 11:10:29浏览次数:1  
标签:23 合并 list1 lists next 链表 升序 list2

目录

题目

  • 给你一个链表数组,每个链表都已经按升序排列。
    请你将所有链表合并到一个升序链表中,返回合并后的链表。

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

法一:暴力

  • 先合并前两个链表,再把得到的新链表和第三个链表合并,再和第四个链表合并,依此类推
// 21. 合并两个有序链表
var mergeTwoLists = function (list1, list2) {
    const dummy = new ListNode(); // 哨兵节点
    let cur = dummy; // 指向新链表的末尾
    while (list1 && list2) {
        if (list1.val < list2.val) {
            cur.next = list1; // 添加 list1 的当前节点
            list1 = list1.next; // 移动 list1
        } else {
            cur.next = list2; // 添加 list2 的当前节点
            list2 = list2.next; // 移动 list2
        }
        cur = cur.next; // 更新新链表的末尾
    }
    cur.next = list1 ? list1 : list2; // 拼接剩余的链表
    return dummy.next; // 返回合并后的链表头节点
};

var mergeKLists = function (lists) {
    if (lists.length === 0) return null; // 如果没有链表,返回 null
    
    let mergedList = lists[0]; // 从第一个链表开始
    // 逐个合并其他链表
    for (let i = 1; i < lists.length; i++) {
        mergedList = mergeTwoLists(mergedList, lists[i]);
    }
    
    return mergedList; // 返回最终合并后的链表
};

法二:递归+分治

  • 把 lists 一分为二,先合并前一半的链表,再合并后一半的链表,然后把这两个链表合并成最终的链表。如何合并前一半的链表呢?我们可以继续一分为二。如此分下去直到只有一个链表,此时无需合并。
// 21. 合并两个有序链表
var mergeTwoLists = function (list1, list2) {
    const dummy = new ListNode(); // 用哨兵节点简化代码逻辑
    let cur = dummy; // cur 指向新链表的末尾
    while (list1 && list2) {
        if (list1.val < list2.val) {
            cur.next = list1; // 把 list1 加到新链表中
            list1 = list1.next;
        } else { // 注:相等的情况加哪个节点都是可以的
            cur.next = list2; // 把 list2 加到新链表中
            list2 = list2.next;
        }
        cur = cur.next;
    }
    cur.next = list1 ? list1 : list2; // 拼接剩余链表
    return dummy.next;
};

var mergeKLists = function (lists) {
    // 合并从 lists[i] 到 lists[j-1] 的链表
    function dfs(i, j) {
        const m = j - i;
        if (m === 0) {
            return null; // 注意输入的 lists 可能是空的
        }
        if (m === 1) {
            return lists[i]; // 无需合并,直接返回
        }
        //Math.floor(m / 2)与(m >> 1)等价
        const left = dfs(i, i + Math.floor(m / 2)); // 合并左半部分
        const right = dfs(i + (m >> 1), j); // 合并右半部分
        return mergeTwoLists(left, right); // 最后把左半和右半合并
    }
    return dfs(0, lists.length);
};

法三、找最小

  • 因为子链表都是升序,每次的最小值一定在子链表的头节点。
var mergeKLists = function(lists) {
    // 创建一个新的链表头
    const mergedHead = new ListNode(0);
    let current = mergedHead;

    while (true) {
        let minIndex = -1;//最小下标
        let minValue = Infinity;//最小值

        // 找到当前所有链表中最小的节点
        for (let i = 0; i < lists.length; i++) {
            //一开始lists[i].val是lists中子链表的头节点
            if (lists[i] && lists[i].val < minValue) {
                minValue = lists[i].val;
                minIndex = i;
            }
        }

        // 如果找到了最小节点,则将其添加到合并链表中
        if (minIndex !== -1) {
            current.next = lists[minIndex];
            current = current.next;
            lists[minIndex] = lists[minIndex].next; // 在该子链表中移动到下一个节点
        } else {
            // 如果没有找到最小节点,说明所有链表都已合并
            break;
        }
    }

    return mergedHead.next; // 返回合并后的链表头
};

标签:23,合并,list1,lists,next,链表,升序,list2
From: https://www.cnblogs.com/lushuang55/p/18663617

相关文章

  • 软件架构师的秘密武器:23个经典案例助你轻松驾驭复杂系统
    设计模式的重要性设计模式,听起来挺高大上的,但其实它就是一些解决常见编程问题的“套路”或“模板”。想象一下你在做饭,有时候你会按照某个固定的步骤来做一道菜,这样既能保证味道好,又省时省力。设计模式在编程中也是这样的作用。设计模式提供了一套经过验证的解决方案,可以在不......
  • 链表的基础操作
    树、链表都是链式结构链表的创建(节点的插入---尾部插入)新建节点判断head指针上是否有数据找到当前链表的最后一个节点,并将新节点放在链表的尾部链表的遍历链表的查找头插法......
  • 不是吧,12306又崩了,3天崩2次,快来看看是什么原因引起的?
    又一次,12306网站崩溃了!这一次竟然在短短3天内发生了两次。每到春运或假期,12306的稳定性总是成为热议话题,然而为何这样的“大型”网站仍频繁出现崩溃现象?它究竟受到了哪些因素的影响?我们来一起分析一下背后的原因。为什么一个技术团队背后支撑着如此庞大的系统,仍然频繁面临崩......
  • 19. 删除链表的倒数第n个节点
    题目卡哥思路卡哥是用双指针来解题,我没想出来这个思路。精华部分:双指针的经典应用,如果要到达倒数第n个节点,让fast移动n步,然后让fast和slow同时移动,直到fast指向链表末尾(nullptr)。slow所指向的节点就是倒数第n个节点。跟着卡哥代码敲了下:/***Definitionforsingly-linked......
  • 省级、地级市、地市州盟保障性住房面积数据(2010-2023年)-社科数据
    省级、地级市、地市州盟保障性住房面积数据(2010-2023年)-社科数据https://download.csdn.net/download/paofuluolijiang/90028565https://download.csdn.net/download/paofuluolijiang/90028565保障性住房是中国政府为解决中低收入家庭住房困难而实施的一项重要政策。这类住房......
  • 160. 相交链表
    [题目连接](160.相交链表-力扣(LeetCode))解题思路:短链表长度为x,长链表长度为y,想让长链表走y-x,然后两个链表同时走,如果相遇直接返回,否则返回空即可。注意,题目明确了,两个链表无环代码classSolution:defgetIntersectionNode(self,headA:ListNode,headB:Li......
  • (免费源码)计算机毕业设计必学必看 万套实战教程 java、python、php、node.js、c#、APP
    摘 要随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,志愿服务管理小程序被用户普遍使用,方便用户能够可以随时进行在线查看志愿服务管理的数据信息管理,特开发了志愿服务管理......
  • FreeRTOS-链表
    链表链表是freertos的一个重要数据结构,后面的任务调度等功能当中,都是基于链表这一项进行的。FreeRTOS的链表是指针指向的链表,一个链表下面有很多链表,每个链表项都有一个指向这个链表的指针。链表实现链表根节点一个链表的数据结构定义如下:typedefstructxLIST{listF......
  • 「GDKOI2023 提高组」异或图
    可以说是计数大杂烩了吧。我们试着进行容斥:每次选定若干条边,钦定这些边两端的值相等。容斥系数显然是\((-1)^{|E|}\)。然后对这些连通块我们把它们的最小值当作\(a_i\)拿来跑异或的问题。实际上我们就是要把原图划分成若干连通块,答案就是每个连通块的容斥系数之积乘上新异或问......
  • XMind2023破解及激活教程(图文版保姆级)
    Xmind应该是目前最好用的一款思维导图软件了。拥有优秀的用户体验,凭借简单易用,功能强大的特点,XMind在2013年被著名互联网媒体Lifehacker评选为全球最受欢迎的思维导图软件。Xmind具有如下优点①、用心打磨16年的思维导图软件②、评分高,多次获得推荐③、装机量超过1亿,深受全......