单手杀穿经典链表题Pt.3——LeetCode天梯渡劫(相交链表,环形链表,随机指针链表的深度拷贝)

本文主要是介绍单手杀穿经典链表题Pt.3——LeetCode天梯渡劫(相交链表,环形链表,随机指针链表的深度拷贝),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

    • 传统艺能😎
    • 相交链表🤔
    • 环形链表🤔
    • 环形链表 II🤔
    • 复制带随机指针的链表🤔

传统艺能😎

小编是双非本科大一菜鸟不赘述,欢迎大佬指点江山(QQ:1319365055)
此前博客点我!点我!请搜索博主 【知晓天空之蓝】
乔乔的gitee代码库(打灰人 )欢迎访问,点我!

🎉🎉非科班转码社区诚邀您入驻🎉🎉
小伙伴们,打码路上一路向北,背后烟火,彼岸之前皆是疾苦
一个人的单打独斗不如一群人的砥砺前行
这是我和梦想合伙人组建的社区,诚邀各位有志之士的加入!!
社区用户好文均加精(“标兵”文章字数2000+加精,“达人”文章字数1500+加精)
直达: 社区链接点我

你一定要走,走到灯火通明

——卢思浩《你要去相信,没有到不了的明天》

在这里插入图片描述

相交链表🤔

链接:相交链表

给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。
题目数据 保证 整个链式结构中不存在环。注意,函数返回结果后,链表必须 保持其原始结构 。如果程序能够正确返回相交节点,那么你的解决方案将被视作正确答案

示例:
在这里插入图片描述

输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,6,1,8,4,5], skipA = 2, skipB = 3
输出:Intersected at ‘8’
解释:相交节点的值为 8 (注意,如果两个链表相交则不能为 0)。
从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,6,1,8,4,5]。
在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。

思路:解题方法比较清奇,有点快慢指针内味,但并非快慢指针,我们要构筑相同路程,为什么?因为两个不等长的链表相交,指针走位不同步就无法比对内容。

只有两个链表不为空是才可能相交,那么链表最后尾节点内容和地址是必然相同的,所以我们重点是同步指针,让他们同时到达尾节点,链表 A 不重叠部分长度为 x,链表 B 不重叠部分长度为 y ,两链表重叠部分长度为 z,遍历两个链表时,A 变成 NULL就让指针指向链表 B 的头结点,B 变成 NULL就让指针指向链表 A 的头结点,抽象个图出来就是这样:

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     struct ListNode *next;* };*/
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {struct ListNode *p1 = headA;struct ListNode *p2 = headB;   while(p1 != p2){if(p1==NULL){p1 = headB;}else{p1 = p1->next;}if(p2==NULL){p2 =headA;}else{p2 =p2->next;}}return p1;
}

~
在这里插入图片描述

环形链表🤔

链接:环形链表

给你一个链表的头节点 head ,判断链表中是否有环。

在这里插入图片描述
思路:有请我们的老朋友:快慢指针!!!在这里插入图片描述
知不知道双指针的含金量啊铁咩!我们既然是环形链表就不怕走到头,只管去找就行了,快指针一次走两步,慢指针一次走一步,遍历的边界就是快指针遍历完两遍链表,这时候慢指针刚好遍历完一遍,如果快指针遇到了慢指针就说明有猫腻。

bool hasCycle(struct ListNode *head) {struct ListNode *slow = head;struct ListNode *fast = head;while(fast && fast->next){slow = slow->next;fast = fast->next->next;if(slow==fast)return  true;}return false;
}

~
在这里插入图片描述

环形链表 II🤔

链接:环形链表 II

给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,不允许修改 链表。

这道题是力扣的中等难度题,他奈奈滴,说的芥末复杂,其实就是在原来判读环形链表基础上多了步找到环形节点罢了。

struct ListNode *detectCycle(struct ListNode *head) {struct ListNode *cur = head;struct ListNode *tail = head;while(tail && tail->next){cur = cur->next;tail = tail->next->next;//判断环形链表if(cur == tail){struct ListNode *head2 = tail;struct ListNode *p1 = head2;struct ListNode *p2 = head;//   tail =NULL;while(p1 != p2){p1 = p1==NULL?head:p1->next;p2 = p2==NULL?head2:p2->next;}//同上上一题,构筑相同路程找到该节点return p1;}
}
return NULL;
}

~
在这里插入图片描述

复制带随机指针的链表🤔

链接:复制带随机指针的链表

给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。

构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next 指针和
random
指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点 。

例如,如果原链表中有 X 和 Y 两个节点,其中 X.random --> Y 。那么在复制链表中对应的两个节点 x 和 y ,同样有
x.random --> y 。 返回复制链表的头节点。

用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 val:一个表示 Node.val 的整数
random_index:随机指针指向的节点索引(范围从 0 到 n-1) 如果不指向任何节点,则为 null 。你的代码 只
接受原链表的头节点 head 作为传入参数。

示例:
在这里插入图片描述
输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
输出:[[7,null],[13,0],[11,4],[10,2],[1,0]]

思路:不开玩笑的说,这道题才配得上力扣给的中等难度,我读懂题目的时候已经老泪纵横了,再看看示例的图直接给我干破防了
在这里插入图片描述

思路:这道题本质就是一个深度拷贝,最大的难点就是如何处理所谓的随机指针,指向随机内容的指针到底该怎么去链接呢?就只有一个办法那就是顺藤摸瓜,从头节点一路向北,不就是复制这个链表吗,那我先创建一个一模一样的链表出来,但是这可不是简简单单复制出来就行,这还是个技术活诶,我们采用尾随式拷贝:
在这里插入图片描述
这种结构的好处就是可以跟进,在复制阶段可以靠拷贝节点的前一个节点(原节点)的随机指针来跟进到复制链表中找到拷贝节点的随机指针,从而达到深度拷贝的目的,逻辑结构就是拷贝节点指向的随机节点是拷贝节点前一个节点的随机指针指向的节点的下一个:
在这里插入图片描述
整个链表就构建完成了,要得到我们的成品就要将原来链表和拷贝链表分离,最后重组拷贝链表就行了。
总结一下就是三步走战略

  1. 原链表每个节点后复制这个节点,与原链表相连形成新链表;
  2. 遍历链表,让 p->next->random = p->random->next ,以此完成链表的拷贝;
  3. 将原链表和拷贝链表拆分,再重组出拷贝链表即可
struct Node* copyRandomList(struct Node* head) {if(head==NULL){return NULL;}//新建拷贝链表struct Node* cur = head;while(cur){struct Node* new = (struct Node*)malloc(sizeof(struct Node));new->val =  cur->val;new->next = cur->next;//与拷贝节点链接成新链表cur->next = new;cur = cur->next->next;}cur = head;//处理random指针while(cur){struct Node* node = cur->next;if(cur->random == NULL){node->random = NULL;}else{node->random = cur->random->next;}cur = cur->next->next;}//重建链表(解下再链接)cur = head;struct Node* copyhead=NULL;struct Node* copytail=NULL;while(cur){struct Node* copy = cur->next;struct Node* next = copy->next;cur->next = next;if(copyhead==NULL){copytail=copyhead=copy;}else{copytail->next = copy;copytail = copytail->next;}cur =next;}
return copyhead;
}

思路理解起来并不难,但是过程中很多细节需要自己去慢慢打磨,这是一个很不错的题目,如果你可以很顺利做出来,那么恭喜你,你对链表的理解已经满分了。

~
在这里插入图片描述

这篇关于单手杀穿经典链表题Pt.3——LeetCode天梯渡劫(相交链表,环形链表,随机指针链表的深度拷贝)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/409936

相关文章

深度解析Java DTO(最新推荐)

《深度解析JavaDTO(最新推荐)》DTO(DataTransferObject)是一种用于在不同层(如Controller层、Service层)之间传输数据的对象设计模式,其核心目的是封装数据,... 目录一、什么是DTO?DTO的核心特点:二、为什么需要DTO?(对比Entity)三、实际应用场景解析

深度解析Java项目中包和包之间的联系

《深度解析Java项目中包和包之间的联系》文章浏览阅读850次,点赞13次,收藏8次。本文详细介绍了Java分层架构中的几个关键包:DTO、Controller、Service和Mapper。_jav... 目录前言一、各大包1.DTO1.1、DTO的核心用途1.2. DTO与实体类(Entity)的区别1

深度解析Python装饰器常见用法与进阶技巧

《深度解析Python装饰器常见用法与进阶技巧》Python装饰器(Decorator)是提升代码可读性与复用性的强大工具,本文将深入解析Python装饰器的原理,常见用法,进阶技巧与最佳实践,希望可... 目录装饰器的基本原理函数装饰器的常见用法带参数的装饰器类装饰器与方法装饰器装饰器的嵌套与组合进阶技巧

深度解析Spring Boot拦截器Interceptor与过滤器Filter的区别与实战指南

《深度解析SpringBoot拦截器Interceptor与过滤器Filter的区别与实战指南》本文深度解析SpringBoot中拦截器与过滤器的区别,涵盖执行顺序、依赖关系、异常处理等核心差异,并... 目录Spring Boot拦截器(Interceptor)与过滤器(Filter)深度解析:区别、实现

深度解析Spring AOP @Aspect 原理、实战与最佳实践教程

《深度解析SpringAOP@Aspect原理、实战与最佳实践教程》文章系统讲解了SpringAOP核心概念、实现方式及原理,涵盖横切关注点分离、代理机制(JDK/CGLIB)、切入点类型、性能... 目录1. @ASPect 核心概念1.1 AOP 编程范式1.2 @Aspect 关键特性2. 完整代码实

C++链表的虚拟头节点实现细节及注意事项

《C++链表的虚拟头节点实现细节及注意事项》虚拟头节点是链表操作中极为实用的设计技巧,它通过在链表真实头部前添加一个特殊节点,有效简化边界条件处理,:本文主要介绍C++链表的虚拟头节点实现细节及注... 目录C++链表虚拟头节点(Dummy Head)一、虚拟头节点的本质与核心作用1. 定义2. 核心价值二

SpringBoot开发中十大常见陷阱深度解析与避坑指南

《SpringBoot开发中十大常见陷阱深度解析与避坑指南》在SpringBoot的开发过程中,即使是经验丰富的开发者也难免会遇到各种棘手的问题,本文将针对SpringBoot开发中十大常见的“坑... 目录引言一、配置总出错?是不是同时用了.properties和.yml?二、换个位置配置就失效?搞清楚加

C++中零拷贝的多种实现方式

《C++中零拷贝的多种实现方式》本文主要介绍了C++中零拷贝的实现示例,旨在在减少数据在内存中的不必要复制,从而提高程序性能、降低内存使用并减少CPU消耗,零拷贝技术通过多种方式实现,下面就来了解一下... 目录一、C++中零拷贝技术的核心概念二、std::string_view 简介三、std::stri

Linux链表操作方式

《Linux链表操作方式》:本文主要介绍Linux链表操作方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、链表基础概念与内核链表优势二、内核链表结构与宏解析三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势六、典型应用场景七、调试技巧与

Python中文件读取操作漏洞深度解析与防护指南

《Python中文件读取操作漏洞深度解析与防护指南》在Web应用开发中,文件操作是最基础也最危险的功能之一,这篇文章将全面剖析Python环境中常见的文件读取漏洞类型,成因及防护方案,感兴趣的小伙伴可... 目录引言一、静态资源处理中的路径穿越漏洞1.1 典型漏洞场景1.2 os.path.join()的陷