大厂真题:【链表】大疆2023秋招-链表合并

news/2024/6/17 11:47:13 标签: 链表, 算法, 数据结构

题目描述与示例

题目描述

现在有一个链表数组,每个链表内都已经是升序的排序现在请你将所有的链表进行合并,返回合并后的升序链表

输入描述

一共 n + 1行数据

1行:一共有 n链表

2~n+1行:所有的链表

输出描述

合并后的链表的所有元素

示例一

输入

3
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

解题思路

注意,本题和LeetCode23. 合并K个升序链表完全一致。

由于采用ACM模式输入,本题的输入直接用数组代替链表,故可以有两种方式进行处理:

  1. 直接对K个升序数组进行K路归并
  2. 将数组转化为链表,再对K个升序链表进行K路归并

在熟练度较高的情况下,建议使用第二种方法,以免通过笔试后,面试官查看代码。

对于K路归并问题,无论是数组还是链表,我们都可以使用优先队列来维护该过程。

代码

解法一:使用链表求解

Python

# 题目:【链表】大疆2023秋招-链表合并
# 作者:闭着眼睛学数理化
算法链表/优先队列
# 代码有看不懂的地方请直接在群上提问


import heapq

# 构建链表节点类
class ListNode:
    def __init__(self, val = 0, next = None):
        self.val = val
        self.next = next

# 根据数组构建链表,返回链表的头节点
def build_linked_list(nums):
    nxt_node = None
    # 采用逆序构建链表的方式最为简单
    # 逆序遍历数组nums,构建值为num的节点node
    # 同时令node指向nxt_node
    for num in nums[::-1]:
        node = ListNode(num, nxt_node)
        nxt_node = node
    return node


# 用于输出链表的函数
def print_linked_list(head):
    node = head
    res = list()
    while(node):
        res.append(node.val)
        node = node.next
    print(" ".join(str(val) for val in res))


# 用于对K个升序链表进行K路归并的函数
def mergeKLists(lists):
    # 构建小根堆,内层元素为二元元组,由每条链表的节点值node.val和链表在lists中的索引i构成
    # 注意到二元元组的排序会先按照第一个元素node.val的大小进行排序
    # 故node.val最小的二元元组会位于小根堆堆顶
    heap = [(node.val, i) for i, node in enumerate(lists) if node]
    heapq.heapify(heap)

    # 构建哑节点,初始化当前节点cur_node为哑节点
    dummyHead = ListNode(0None)
    cur_node = dummyHead
    # 持续进行循环,退出循环的条件为heap为空
    while (heap):
        # 弹出值最小的元素,即当前lists中最小的节点
        cur_min_node, idx = heapq.heappop(heap)
        # 当前节点指向节点lists[idx]
        cur_node.next = lists[idx]
        # 当前节点cur_node前进
        cur_node = cur_node.next
        # 在lists中索引idx对应的节点前进
        lists[idx] = lists[idx].next
        # 如果前进后的节点lists[idx]不为空节点,
        # 则同样按照(node.val, i)的格式压入堆中
        if lists[idx]:
            heapq.heappush(heap, (lists[idx].val, idx))

    # 最终返回哑节点dummyHead的下一个节点,为合并后的链表的头节点
    return dummyHead.next

# 输入链表条数k
k = int(input())
# 储存k条链表的数组lists
lists = list()
# 遍历k次,将输入的数组nums转化为链表head
# 再将head存入lists中
for _ in range(k):
    nums = list(map(int, input().split()))
    head = build_linked_list(nums)
    lists.append(head)

# 调用mergeKLists()函数,得到合并后的新的头节点
final_head = mergeKLists(lists)
print_linked_list(final_head)

Java


C++


时空复杂度

时间复杂度:O(kNlog⁡k)。考虑优先队列中的元素不超过k个,那么插入和删除的时间代价为O(log⁡k),这里最多有 kN个点,对于每个点都被插入删除各一次,故总的时间代价即渐进时间复杂度为 O(kn×log⁡k)

空间复杂度:O(k)。这里用了优先队列,优先队列中的元素不超过 k 个,故渐进空间复杂度为O(k)

解法二:使用数组求解

Python

# 题目:【链表】大疆2023秋招-链表合并
# 作者:闭着眼睛学数理化
算法:数组/优先队列
# 代码有看不懂的地方请直接在群上提问


import heapq


# 用于对K个升序数组进行K路归并的函数
def mergeKLists(lists):
    # 构建小根堆,内层元素为二元元组,由每个数组nums首元素的值nums[0]和其在lists中的索引i构成
    # 注意到二元元组的排序会先按照第一个元素nums[0]的大小进行排序
    # 故nums[0]最小的二元元组会位于小根堆堆顶
    heap = [(nums[0], i) for i, nums in enumerate(lists)]
    heapq.heapify(heap)
    # 表示每一个数组nums进行到哪一个索引的数字idx_lst,初始化均为0
    # 表示最开始时,都位于0索引的位置
    # 长度为数组nums的数量,即len(lists)
    idx_lst = [0] * len(lists)
    ans = list()
    while heap:
        # 弹出值最小的元素,即当前lists中最小的数组
        cur_min_num, idx = heapq.heappop(heap)
        # cur_min_num为加入ans的元素
        ans.append(cur_min_num)
        # 在lists中索引为idx的数组lists[idx]里的索引idx_lst[idx]需要前进一步
        idx_lst[idx] += 1
        # 如果idx_lst[idx]前进后,没有到达
        # 则同样按照(num, i)的格式压入堆中
        # 其中num = lists[idx][idx_lst[idx]]
        # lists[idx]为第idx个数组,选取该数组中第idx_lst[idx]个数
        if idx_lst[idx] != len(lists[idx]):
            num = lists[idx][idx_lst[idx]]
            heapq.heappush(heap, (num, idx))
    return ans


# 输入链表条数k
k = int(input())
# 储存k个链表的数组lists,此处用数组代替链表
lists = list()
# 遍历k次,直接储存数组nums
for _ in range(k):
    nums = list(map(int, input().split()))
    lists.append(nums)

ans = mergeKLists(lists)
print(" ".join(str(num) for num in ans))

Java


C++


华为OD算法/大厂面试高频题算法练习冲刺训练

  • 华为OD算法/大厂面试高频题算法冲刺训练目前开始常态化报名!目前已服务100+同学成功上岸!

  • 课程讲师为全网50w+粉丝编程博主@吴师兄学算法 以及小红书头部编程博主@闭着眼睛学数理化

  • 每期人数维持在20人内,保证能够最大限度地满足到每一个同学的需求,达到和1v1同样的学习效果!

  • 60+天陪伴式学习,40+直播课时,300+动画图解视频,300+LeetCode经典题,200+华为OD真题/大厂真题,还有简历修改、模拟面试、专属HR对接将为你解锁

  • 可上全网独家的欧弟OJ系统练习华子OD、大厂真题

  • 可查看链接 OD算法冲刺训练课程表 & OD真题汇总(持续更新)

  • 绿色聊天软件戳 od1336了解更多


http://www.niftyadmin.cn/n/5099403.html

相关文章

idea无法通过vpn连接到数据库

本人之前遇到情况当打开vpn时,使用工具navicat可以连接到数据库,但是IDEA连接不到。这就很奇怪了,于是在网上大量搜寻解决方案,终于找到: 连接异常: 因为是Springboot项目,可以在启动类的配置…

目标跟踪数据集分享

360VOT: A New Benchmark Dataset for Omnidirectional Visual Object Tracking 360VOT 是一个新的大规模全景追踪基准数据集,旨在为全景视觉物体追踪提供支持。这个数据集包含了 120 个序列,总计超过 11.3 万张高分辨率帧,采用等距投影。追踪…

Unity3D 如何自己编写一个URP渲染管线的Shader详解

Unity3D是一款强大的游戏开发引擎,它提供了许多渲染管线供开发者选择使用。其中一种渲染管线是Universal Render Pipeline (URP),它是一种轻量级的渲染管线,适用于移动设备和低端硬件。在本文中,我们将详细介绍如何自己编写一个UR…

药物滥用第一篇介绍

AMP: Ampicillin,中文名氨苄青霉素,同义名氨苄西林,一种β-内酰胺类抗生素,属于青霉素家族的一员,化学式为C16H19N3O4S,可治疗多种细菌感染。 氨苄西林为半合成的广谱青霉素(结构如上…

【二层环路】交换机二次原路排查思路

以太网交换网络中为了提高网络可靠性,通常会采用冗余设备和冗余链路,然而现网中由于组网调整、配置修改、升级割接等原因,经常会造成数据或协议报文环形转发,不可避免的形成环路。如图1所示,三台设备两两相连就会形成环…

简单方法建立个人网站,不用编程

对于很多没有编程知识的小白来说,建立个人网站似乎是一件困难而遥远的事情。然而,现在有了一个无需编程的方法,小白也能够轻松建立自己的个人网站,让自己的才华和创意得到更好的展示! 首先,你需要登录乔拓云…

智能体、多模态化大势所趋,探大模型的未来!

导语 | 今年以来,以 ChatGPT 为代表的生成式 AI,在最具挑战性的自然语言处理领域实现革命性突破,在行业掀起新一轮发展热潮。开源大模型正成为人工智能领域的新潮流,AI 大模型在未来将走向何方?今天,我们特…

SW中的面部曲线命令

今天学习老王的画图教程中看到在使用面部曲线命令,找了变天没有,于是开始四处查找模式,终于在一个视频中看到了,原来不是在曲面命令中,而是在草图命令中,老王为了迷惑学员,把这个面部曲线命令放…