【数据结构与算法】【腾讯阿里链表面试题】算法题--链表易懂版讲解

简介: 【数据结构与算法】【腾讯阿里链表面试题】算法题--链表易懂版讲解

腾讯面试题:复制随机节点


题目说明:


给定一个链表,每个节点包含一个指向任意节点的随机指针,同时每个节点有一个指向同一链表中节点的指针,输出这个链表的深拷贝。


输入示例:

输入:
Node* p = new Node(p1);
p1 = new Node(p2);
p2 = new Node(p3);
p3 = new Node(null);
// 随机连接
p->random = p2;
p1->random = null;
p2->random = p3;
 
Node* clone = cloneRandomNode(p);


输出示例:


返回与原链表相同结构的复制链表,并正确设置每个节点的随机指针。


时间复杂度:O(n)


  • 其中 n 是链表的长度,我们需要遍历整个链表一次来创建复制品。


空间复杂度:O(n)


  • 存储复制的节点需要额外的空间。


解析


题目分析:


这个问题要求我们复制一个链表,其中每个节点包含一个指向任意节点的随机指针。我们需要返回这个链表的深拷贝,并正确设置每个节点的随机指针。


解题过程:


  1. 首先,我们遍历原始链表,对于每个节点,创建一个新节点,并将其插入到原节点的后面。这样我们就可以同时访问原始节点和新节点。例如,原始链表为 1 -> 2 -> 3,复制后变为 1 -> 1' -> 2 -> 2' -> 3 -> 3'
原始链表:   1 -> 2 -> 3
复制后的链表: 1' -> 2' -> 3'
  1. 然后,我们再次遍历链表,这次是为了设置每个新节点的随机指针。我们根据原节点的随机指针找到对应的新节点,并将其设置为新节点的随机指针。例如,如果原节点 2 的随机指针指向 3,那么新节点 2' 的随机指针应该指向 3'
原始链表:   1 -> 2 -> 3
复制后的链表: 1' -> 2' -> 3'
随机指针:    N -> 2 -> N
复制后的随机指针: N -> 2' -> N
  1. 最后,我们将新旧节点分离,并返回复制链表的头节点。例如,将 1 -> 1' -> 2 -> 2' -> 3 -> 3' 分离成 1 -> 2 -> 31' -> 2' -> 3',然后返回 1' 作为复制链表的头节点。
原始链表:   1 -> 2 -> 3
复制后的链表: 1' -> 2' -> 3'
分离后的链表: 1 -> 2 -> 3
分离后的复制链表: 1' -> 2' -> 3'
返回头节点: 1'
class Node:
    def __init__(self, val=0, next=None, random=None):
        self.val = val
        self.next = next
        self.random = random
 
def cloneRandomNode(head):
    if not head:
        return None
    
    # 第一步:复制每个节点,并将新节点插入原节点后面
    curr = head
    while curr:
        new_node = Node(curr.val)
        new_node.next = curr.next
        curr.next = new_node
        curr = new_node.next
    
    # 第二步:设置每个新节点的随机指针
    curr = head
    while curr:
        curr.next.random = curr.random.next if curr.random else None
        curr = curr.next.next
    
    # 第三步:分离新旧节点,返回复制链表的头节点
    curr = head
    new_head = head.next
    while curr:
        next_old = curr.next
        next_new = curr.next.next
        curr.next = next_new
        if next_new:
            curr.next.next = next_old
        curr = next_old
    
    return new_head


阿里巴巴面试题:合并K个排序链表


题目说明:


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

复制代码
输入:
lists = [[1,4,5],[1,3,4],[2,6]]


输出示例:


输出:[1,1,2,3,4,4,5,6]


时间复杂度:O(N*log(k))


  • 其中 N 是所有链表中元素的总数,k 是链表的个数。假设使用最小堆处理每个链表的头部元素。


空间复杂度:O(k)


  • 存储 k 个链表头部节点所需的空间。


解析


题目分析:


这个问题要求我们合并 k 个已排序的链表,并返回一个新的升序链表。我们可以使用分治法来解决这个问题。


解题过程:


  1. 我们使用最小堆来存储每个链表的头部节点。这样可以快速地找到当前最小的节点。例如,如果有三个链表分别为 1 -> 4 -> 51 -> 3 -> 42 -> 6,则最小堆中的元素为 (1, node1)(1, node2)(2, node3)
链表1:       1 -> 4 -> 5
链表2:       1 -> 3 -> 4
链表3:       2 -> 6
最小堆:      (1, node1), (1, node2), (2, node3)
  1. 我们创建一个虚拟头节点 dummy,用于连接所有合并后的节点。


  1. 我们不断从最小堆中取出最小的节点,将其连接到结果链表中,并将该节点的下一个节点加入堆中,直到堆为空。例如,我们从最小堆中取出 (1, node1),将其连接到结果链表中,然后将 node1.next(即值为 4 的节点)加入堆中。
结果链表:     dummy -> 1
最小堆:      (1, node2), (4, node4), (6, node6)
  1. 最后,我们返回合并后链表的头节点。例如,最终的结果链表为 1 -> 1 -> 2 -> 3 -> 4 -> 4 -> 5 -> 6,返回 dummy.next
结果链表:     1 -> 1 -> 2 -> 3 -> 4 -> 4 -> 5 -> 6
返回头节点:   1
import heapq
from typing import List, Optional
 
class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next
 
def mergeKLists(lists: List[Optional[ListNode]]) -> Optional[ListNode]:
    if not lists:
        return None
    
    # 使用最小堆来存储每个链表的头部节点
    min_heap = []
    for node in lists:
        if node:
            heapq.heappush(min_heap, (node.val, node))
    
    dummy = ListNode()
    current = dummy
    
    # 每次从堆中取出最小的节点,将其连接到结果链表中,并将该节点的下一个节点加入堆中
    while min_heap:
        val, node = heapq.heappop(min_heap)
        current.next = ListNode(val)
        current = current.next
        if node.next:
            heapq.heappush(min_heap, (node.next.val, node.next))
    
    return dummy.next
相关文章
|
6月前
|
人工智能 算法 语音技术
Video-T1:视频生成实时手术刀!清华腾讯「帧树算法」终结闪烁抖动
清华大学与腾讯联合推出的Video-T1技术,通过测试时扩展(TTS)和Tree-of-Frames方法,显著提升视频生成的连贯性与文本匹配度,为影视制作、游戏开发等领域带来突破性解决方案。
194 4
Video-T1:视频生成实时手术刀!清华腾讯「帧树算法」终结闪烁抖动
|
11月前
|
算法 前端开发 Java
数据结构与算法学习四:单链表面试题,新浪、腾讯【有难度】、百度面试题
这篇文章总结了单链表的常见面试题,并提供了详细的问题分析、思路分析以及Java代码实现,包括求单链表中有效节点的个数、查找单链表中的倒数第k个节点、单链表的反转以及从尾到头打印单链表等题目。
121 1
数据结构与算法学习四:单链表面试题,新浪、腾讯【有难度】、百度面试题
|
算法 Java
Java面试题:解释垃圾回收中的标记-清除、复制、标记-压缩算法的工作原理
Java面试题:解释垃圾回收中的标记-清除、复制、标记-压缩算法的工作原理
209 1
|
算法 Java 程序员
Java面试题:解释Java的垃圾回收机制,包括常见的垃圾回收算法。介绍一下Java的垃圾回收算法中的标记-压缩算法。
Java面试题:解释Java的垃圾回收机制,包括常见的垃圾回收算法。介绍一下Java的垃圾回收算法中的标记-压缩算法。
119 0
|
算法 Java 开发者
Java面试题:Java内存探秘与多线程并发实战,Java内存模型及分区:理解Java堆、栈、方法区等内存区域的作用,垃圾收集机制:掌握常见的垃圾收集算法及其优缺点
Java面试题:Java内存探秘与多线程并发实战,Java内存模型及分区:理解Java堆、栈、方法区等内存区域的作用,垃圾收集机制:掌握常见的垃圾收集算法及其优缺点
103 0
|
存储 Java
【IO面试题 四】、介绍一下Java的序列化与反序列化
Java的序列化与反序列化允许对象通过实现Serializable接口转换成字节序列并存储或传输,之后可以通过ObjectInputStream和ObjectOutputStream的方法将这些字节序列恢复成对象。
|
10月前
|
存储 算法 Java
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
本文详解自旋锁的概念、优缺点、使用场景及Java实现。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
|
10月前
|
存储 缓存 算法
面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!
本文介绍了多线程环境下的几个关键概念,包括时间片、超线程、上下文切换及其影响因素,以及线程调度的两种方式——抢占式调度和协同式调度。文章还讨论了减少上下文切换次数以提高多线程程序效率的方法,如无锁并发编程、使用CAS算法等,并提出了合理的线程数量配置策略,以平衡CPU利用率和线程切换开销。
面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!
|
10月前
|
存储 缓存 Java
大厂面试必看!Java基本数据类型和包装类的那些坑
本文介绍了Java中的基本数据类型和包装类,包括整数类型、浮点数类型、字符类型和布尔类型。详细讲解了每种类型的特性和应用场景,并探讨了包装类的引入原因、装箱与拆箱机制以及缓存机制。最后总结了面试中常见的相关考点,帮助读者更好地理解和应对面试中的问题。
249 4
|
11月前
|
算法 Java 数据中心
探讨面试常见问题雪花算法、时钟回拨问题,java中优雅的实现方式
【10月更文挑战第2天】在大数据量系统中,分布式ID生成是一个关键问题。为了保证在分布式环境下生成的ID唯一、有序且高效,业界提出了多种解决方案,其中雪花算法(Snowflake Algorithm)是一种广泛应用的分布式ID生成算法。本文将详细介绍雪花算法的原理、实现及其处理时钟回拨问题的方法,并提供Java代码示例。
863 2

热门文章

最新文章