【数据结构】:大厂面试经典链表OJ题目详解

image.png

反转链表

206. 反转链表 - 力扣(LeetCode)
image.png|488

思路解透

image.png|447
本题就是通过不停地将最先的 head 节点位置的后一位插到最前面,完成链表的反转
本题需要两个节点变量

  1. cur:其任务就是定位到 head 节点位置的前一位,然后将自己插入到当前 head 节点的前面
    • 因为链表的最后一个节点都是指向一个 null 值,所以需要将最先的 head 节点的 next 置为空
    • 但在将 head.next 置为 null 之前,需要先将 cur 节点实例化出来,不然 cur 就无法找到原先的 head 节点的位置了
  2. curN:其任务就是定位到 cur 的后一个节点,方便让 cur 进行循环插入
    • 其在循环中进行实例化,因为每一次插入完成之后,curN 的位置都是需要随着 cur 的改变而改变
    • curN 实例化为 cur 的下一个节点。在 cur 插入完成后,cur 就会定位到 curN 的位置,若此为止不为 null,则继续进行前插

代码解析

class Solution {public ListNode reverseList(ListNode head) {//1. 防止空指针异常  if(head == null){  return head;  	}  //2. 将head.next置为空  //注意先把 cur 节点给先弄出来  ListNode cur = head.next;  head.next = null;  //3. 进行循环头插  while (cur != null) {  ListNode curN = cur.next;  cur.next = head;  head = cur;  cur = curN;  }  return head;}
}

寻找中间节点

876. 链表的中间结点 - 力扣(LeetCode)
image.png|613

思路解透

解法 1:定义一个 cur 节点,从 head 节点的地方,向后走 size()/2 步,就到了中间位置
解法 2:定义一个 slow 节点,一次走一步,在定义一个 fast 节点,一次走两步,当 fast 走完的时候,slow 就刚好在中间位置(快慢指针

  • 当有偶数个节点时,循环判断条件为:fast != null
  • 当有奇数个节点时,循环判断条件为:fast.next != null
  • 这里的两个条件判断顺序不能换,否则会报空指针异常错误

快慢指针原理:
路程一样的情况下,速度是两倍,那么当走完的时候,路程也是两倍

代码解析(法 1)

public ListNode middleNode(){  int count = 0;  ListNode node = head;  while(node != null){  count++;  node = node.next;  }    ListNode cur = head;  for (int i = 0; i < count/2; i++) {  cur = cur.next;  }    return cur;  
}

代码解析(法 2)

public ListNode middleNode(){  ListNode slow = head;  ListNode fast = head;  while(fast != null && fast.next != null){  //slow走一步,fast走两步slow = slow.next;  fast = fast.next.next;  }    return slow;  
}

返回链表中倒数第 k 个节点

面试题 02.02. 返回倒数第 k 个节点 - 力扣(LeetCode)
image.png|533

思路解透

  1. 首先判断 k 是否合法,链表是否为为 null
    1. k <= 0,返回-1
    2. (下面的第二点看完再回来)因为如果 k 大于链表长度的话,当 fastk - 1 步的时候就会走出链表,所以在 fastk-1 步的过程中如果出现 fast == null,则返回 -1
  2. 定义两个节点,fast 先走 k - 1 步,随后 fastslow 一起走,当 fast 走到最后了,slow 所在的地方就是倒数第 k 个节点

代码解析

public int kthToLast(int k) {  //判断k是否合法,链表是否为nullif(k <= 0 || head == null) {  return -1;  }    ListNode fast = head;  ListNode slow = head;  int count = 0;  while (count != k - 1) {  //fast先向后走k-1步        fast = fast.next;  if(fast == null){//判断k是否合法return -1;  }count++;  }    while (fast.next != null){//两个节点一起向后走,直到fast走到最后一个  fast = fast.next;  slow = slow.next;  }    return slow.val;  
}

合并两个有序链表

21. 合并两个有序链表 - 力扣(LeetCode)
image.png|546

思路解透

创建一个新的链表,为虚拟节点(傀儡节点),然后对需要合并的两个链表中的值进行比较,谁小谁就接在虚拟节点后面

  1. 创建一个新的节点 newH,在这个链表上进行合并,再创建一个 tmp 节点,用来指向 newH 链表中的最后一个节点
  2. headA != null && headB != null 的时候,进行比较
    1. headA. val < headB. val,则将 headA 这个节点接在 newH 后面,即接在 tmp 节点后面,最后 tmpheadB 节点均向后移一位
    2. headA. val > headB. val,则将 headB 这个节点接在 newH 后面,即接在 tmp 节点后面,最后 tmpheadB 节点均向后移一位
  3. headA == null || headB == null 的时候,剩下的一个链表里面的节点直接接到 newH 后面就行了
  4. 最后返回 newH. next,因为 newH 是一个虚拟节点,不存在于要合并的链表中,它只是一个引子

代码解析

public ListNode mergeTwoLists(ListNode headA, ListNode headB) {  ListNode newH = new ListNode(0);  ListNode tmp = newH;  while(headA != null && headB != null){  if(headA.val < headB.val){  //将headA接到newH上面,随后后移tmp.next = headA;  headA = headA.next;  tmp = tmp.next;  }else if{  //将headB接到newH上面,随后后移tmp.next = headB;  headB = headB.next;  tmp = tmp.next;  }    }    if(headA == null){  //headA空了,将headB直接接到newH后面tmp.next = headB;  }    //headB空了,将headA直接接到newH后面if (headB == null) {  tmp.next = headA;  }    return newH.next;  
}

分割链表

链表分割_牛客题霸_牛客网 (nowcoder.com)
image.png

思路解透

构建两个区间,一个里面接上小于 x 的节点,一个里面接上大于 x 的节点,最后将这两个区间连接起来

  1. 若链表为空
  2. 遍历链表
    • 创建一个 cur 节点,用来遍历链表
  3. 把对应的节点放到指定区间
    1. 在小区间里
      1. 创建 bs(before start) 节点指向区间里面最前面的一个节点,创建 be(before end) 节点指向区间里面最后一个节点
      2. 在小区间里面插入第一个节点的时候,bsbe 都指向这个节点,随后 cur 向后移
      3. 之后插入的节点均为尾插,bs 位置不变,be 始终指向新插入的节点
    2. 在大区间里
      1. 创建 as(after start) 节点指向区间里面最前面的一个节点,创建 ae(after end) 节点指向区间里面最后一个节点
      2. 在小区间里面插入第一个节点的时候,asae 都指向这个节点,随后 cur 向后移
      3. 之后插入的节点均为尾插,as 位置不变,ae 始终指向新插入的节点
  4. 把两个区间连接起来
    1. be 节点和 as 节点连接起来,并且将 ae 节点的 next 置为 null,作为新链表的尾巴,并且返回 bs 节点
    2. 若所有节点全在小区间里,就将 be 节点的 next 置为 null,作为新链表的尾巴,并且返回 bs 节点
    3. 若全在大区间里,则返回 ae 节点

代码解析

public ListNode partition(ListNode pHead, int x) {  //判断空链表if(pHead == null){  return null;  }      //小区间的两个节点ListNode bs = null;  ListNode be = null;  //大区间的两个节点ListNode as = null;  ListNode ae = null;  //遍历链表的节点ListNode cur = pHead;  while(cur != null){  //插入小区间if(cur.val < x){  //第一次插入if(bs == null){  bs = be = cur;  }else{  be.next = cur;  be = be.next;  } //插入大区间       }else{  //第一次插入if(as == null){  as = ae = cur;  }else{  ae.next = cur;  ae = ae.next;  }        }        cur = cur.next;  }    //当节点全部都在小区间时,直接返回大区间if(bs == null){  return as;  }    //进行大小区间的拼接be.next = as;  //大区间不为空,把最后一个节点置空,作为尾巴if(as != null){  ae.next = null;  }  return bs;  
}

回文链表

链表的回文结构_牛客题霸_牛客网 (nowcoder.com)
image.png|579

思路解透

  1. 首先用快慢指针找到中间的节点(上面第二题有讲解)
  2. 再对后半部分进行反转(上面第一题有讲解)
  3. 最后让首尾两个节点往中间走,直到相遇,返回 true;若是偶数个节点,则只需要前面节点的 next 与后面节点的值相等即可返回 true

代码解析

public boolean chkPalindrome(ListNode head) {  // write code here  if (head == null) {  return true;  }  //1. 找到链表的中间节点  ListNode fast = head;  ListNode slow = head;  while (fast != null && fast.next != null) {  slow = slow.next;  fast = fast.next.next;  }  //2. 反转后半节点  ListNode cur = slow.next;  slow.next = null;  while (cur != null) {  ListNode curN = cur.next;  cur.next = slow;  slow = cur;  cur = curN;  }  //3. slow从后往前,head从前往后,直到相遇  while (head != slow) {  if (head.val != slow.val) {  return false;  }        //当节点个数为偶数if (head.next == slow)  return true;  head = head.next;  slow = slow.next;  }    return true;  
}

相交链表

160. 相交链表 - 力扣(LeetCode)
image.png|572

思路解透

  1. 首先计算两个链表的长度,并计算他们的差值
  2. 随后让长的链表的头节点先走“差值“步,让他们站在同一起跑线
  3. 最后让他们携手同行,直到相遇,返回任意一个链表;若最终零个引用都为空,证明不相交,返回 null

代码解析

public ListNode getIntersectionNode(ListNode headA, ListNode headB) {  //1. 计算两个链表的长度,并计算差值  int lenA = 0;  int lenB = 0;  ListNode curA = headA;  ListNode curB = headB;  while (curA != null) {  curA = curA.next;  lenA++;  }    while (curB != null) {  curB = curB.next;  lenB++;  }    int len = lenA - lenB;  curA = headA;  curB = headB;  //2. 根据差值,长的链表头节点先走len步,  // 让两个链表在同一起跑线  if (len > 0) {  int count = 0;  while (count != len) {  curA = curA.next;  count++;  }    } else {  int count = 0;  while (count != -len) {  curB = curB.next;  count++;  }    }  //3. 两个链表的节点携手同行,直到相等  while (curA != curB) {  curA = curA.next;  curB = curB.next;  }    if (curA == null) {  //若两个引用都为空,证明不相交  return null;  }    return curA;  
}

环形链表

141. 环形链表 - 力扣(LeetCode)
image.png|527

思路解透

  1. 定义两个节点,一个一次走一步,一个一次走两步
  2. 当走得快的节点不为空,并且走得快的节点的 next 不为空,循环就一直继续
  3. 当两个节点相等,则返回 true

假设链表带环,两个指针最后都会进入环,快指针先进环,慢指针后进环。当慢指针刚进环时,可能就和快指针相遇了,最差情况下两个指针之间的距离刚好就是环的长度。此时,两个指针每移动一次,之间的距离就缩小一步,不会出现每次刚好是套圈的情况
因此:在慢指针走到一圈之前,快指针肯定是可以追上慢指针的,即相遇。

代码解析

public boolean hasCycle(ListNode head) {  ListNode fast = head;  ListNode slow = head;  while(fast != null && fast.next != null){  fast = fast.next.next;  slow = slow.next;  if(fast == slow)  return true;  }    return false;  
}

环形链表Ⅱ

142. 环形链表 II - 力扣(LeetCode)
image.png|528

思路解透

image.png|626

代码解析

public ListNode detectCycle(ListNode head) {  //1. 判断是否有环  ListNode fast = head;  ListNode slow = head;  while (fast != null && fast.next != null) {  fast = fast.next.next;  slow = slow.next;  //有环,跳出循环  if (fast == slow) {  break;  }    }    //若是因为没有环而跳出循环的话,返回null  if (fast == null || fast.next == null) {  return null;  }    //此时slow在相遇点,将fast拿到起始点  //让他们相向而行,相遇点即为入口点  fast = head;  while(fast != slow) {  fast = fast.next;  slow = slow.next;  }    return fast;  
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/3268659.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

百日筑基第二十八天-23种设计模式-行为型总汇

百日筑基第二十八天-23种设计模式-行为型总汇 文章目录 百日筑基第二十八天-23种设计模式-行为型总汇前言模板方法模式简介模板方式的特点模板方法模式结构类图模板方式模式案例分析模板方法模式应用源码分析模板方法模式的注意事项和细节 迭代器模式迭代器模式结构类图迭代器模…

git配置环境变量

一.找到git安装目录 打开此git安装目录下的bin文件&#xff0c;复制此文件路径 二.配置环境变量 2.1 右键点击此电脑的属性栏 2.2 点击高级系统配置 2.3 点击环境变量 2.4 按图中步骤进行配置 三.配置完成 win r 输入cmd打开终端 终端页面中输入 git --version 如图所示…

给定日期计算时间(2025新年倒计时)

目录 1.安装所需安装包 2.查看安装包是否安装成功 ​ 3.使用 Pandas 读取数据文件 4.定义图像背景 5.matplotlib输出 6.当前指定格式时间 7.2025新年倒计时 1.安装所需安装包 pip install 包名 2.查看安装包是否安装成功 python -m pip list ​ 3.使用 Pandas 读取数…

深度解析Linux-C——结构体(初始化,结构体数组,结构体大小,位段操作,联合体,内存对齐,C的预处理,宏和带参宏,条件编译)

目录 结构体的三种初始化 结构体的两种引用 结构体数组 结构体大小 结构体实现位段操作 联合体 内存对齐 C的预处理 带参宏 条件编译 结构体的三种初始化 定义如下结构体 struct student {char name[100]; int age; float height; } ; 1、定义变量时初始化 s…

Redis从入门到超神-(十二)Redis监听Key的过期事件

前言 试想一个业务场景&#xff0c;订单超过30分钟未支付需要做自动关单处理,修改订单状态&#xff0c;库存回退等&#xff0c;你怎么实现&#xff1f;方案一&#xff1a;可以使用定时任务扫表&#xff0c;通过支付状态和下单时间来判断是否支付过期。但是这样的方案是非常消耗…

推荐一款.NET开源、简洁易用的Windows桌面小说阅读应用

前言 今天大姚给大家分享一款.NET开源、免费、简洁易用的Windows桌面小说阅读应用(是原生的 Windows 应用&#xff0c;为 Windows 11 系统设计)&#xff1a;CleanReader.Desktop。 该应用适合喜欢阅读网文或者是本地轻量阅读的用户。 系统要求 操作系统&#xff1a;Windows 11…

Llama + Dify,在你的电脑搭建一套AI工作流

theme: smartblue 点赞 关注 收藏 学会了 本文简介 最近字节在推Coze&#xff0c;你可以在这个平台制作知识库、制作工作流&#xff0c;生成一个具有特定领域知识的智能体。 那么&#xff0c;有没有可能在本地也部署一套这个东西呢&#xff1f;这样敏感数据就不会泄露了&…

Linux之基础IO(下)

目录 缓冲区的概念 深入理解文件系统 创建文件的整个过程 软链接 硬链接 上一节课我们学习了基础IO中的文件的读写操作&#xff0c;以及文件描述符的概念和重定向的基本原理&#xff0c;本期我们继续进行基础IO的学习。 缓冲区的概念 在讲缓冲区之前&#xff0c;大家先看…

Redis实战篇(黑马点评)笔记总结

一、配置前后端项目的初始环境 前端&#xff1a; 对前端项目在cmd中进行start nginx.exe&#xff0c;端口号为8080 后端&#xff1a; 配置mysql数据库的url 和 redis 的url 和 导入数据库数据 二、登录校验 基于Session的实现登录&#xff08;不推荐&#xff09; &#xf…

C++ - char*、const char*、char[]、string

const char* const char* 用来定义字符串常量。 char[ ] char型的字符数组是一种定长的数组&#xff0c;存储指定长度的字符序列&#xff0c;数组中的每个元素都是一个char类型的变量&#xff0c;如&#xff1a; char arr[] {h, a, l, l, o, \0}; char c arr[0]; // 访问…

使用 Windows 应用程序 SDK 构建下一代应用程序

微软面临的最大问题之一是如何让 Windows 再次成为吸引开发者的平台。无论用户使用什么设备和操作系统&#xff0c;都可以很容易地将 Web 前端放在支持桌面和移动用户的云原生应用程序上。 我们处在一个奇怪的境地&#xff0c;唯一能利用最新 PC 硬件的应用程序是 Office、Phot…

【中项第三版】系统集成项目管理工程师 | 第 11 章 规划过程组⑤ | 11.13 - 11.14

前言 第11章对应的内容选择题和案例分析都会进行考查&#xff0c;这一章节属于10大管理的内容&#xff0c;学习要以教材为准。本章上午题分值预计在15分。 目录 11.13 制定预算 11.13.1 主要输入 11.13.2 主要输出 11.14 规划质量管理 11.14.1 主要输入 11.14.2 主要工…

HTML前端面试题之<iframe>标签

面试题&#xff1a;iframe 标签的作用是什么?有哪些优缺点 ? 讲真&#xff0c;刷这道面试题之前我根本没有接触过iframe&#xff0c;网课没讲过&#xff0c;项目实战没用过&#xff0c;但却在面试题里出现了&#xff01;好吧&#xff0c;我只能说&#xff1a;前端路漫漫&…

数据挖掘-数据预处理

来自&#x1f96c;&#x1f436;程序员 Truraly | 田园 的博客&#xff0c;最新文章首发于&#xff1a;田园幻想乡 | 原文链接 | github &#xff08;欢迎关注&#xff09; 文章目录 3.3.1 数据的中心趋势平均数和加权平均数众数&#xff0c;中位数和均值描述数据的离散程度 &a…

快速搞定分布式RabbitMQ---RabbitMQ进阶与实战

本篇内容是本人精心整理&#xff1b;主要讲述RabbitMQ的核心特性&#xff1b;RabbitMQ的环境搭建与控制台的详解&#xff1b;RabbitMQ的核心API&#xff1b;RabbitMQ的高级特性;RabbitMQ集群的搭建&#xff1b;还会做RabbitMQ和Springboot的整合&#xff1b;内容会比较多&#…

火山引擎云搜索服务通过信通院向量数据库可信认证

7月16日&#xff0c;首届线下“可信数据库发展大会”在北京举办&#xff0c;会上中国信息通信研究院&#xff08;中国信通院&#xff09;公布了 2024 上半年“可信数据库”产品能力评测结果。火山引擎云搜索服务在基本功能、运维管理、安全性、兼容性、扩展性、高可用、工具生态…

【LeetCode 随笔】C++入门级,详细解答加注释,持续更新中。。。

文章目录 58.【简单】最后一个单词的长度&#x1f31f; &#x1f308;你好呀&#xff01;我是 山顶风景独好 &#x1f388;欢迎踏入我的博客世界&#xff0c;能与您在此邂逅&#xff0c;真是缘分使然&#xff01;&#x1f60a; &#x1f338;愿您在此停留的每一刻&#xff0c;都…

Html+Css网页开发之动态登录页面(默认Chrome)

>>效果展示图<< 一、需求分析与设计要求 实现了一个动态背景图案的效果&#xff0c;包括一个白色的容器&#xff0c;内部有一个标题、一个输入框、一个按钮和一些文本。 背景是一个渐变色的线性渐变&#xff0c;而在容器的周围&#xff0c;有一些随机的方形和圆形图…

Element快速学习

博客主页&#xff1a;音符犹如代码系列专栏&#xff1a;JavaWeb关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ 什么是Element&#xff1f; Element&#xff1a;它是由饿了么团队开发的一个…

Dubbon-微服务通信(基本简介 基础实现)

目录 一、基本简介 二、基础实现 1. 提供统⼀业务api 2. 编辑服务提供者product 3. 编辑服务消费者order 4. 服务调⽤测试 一、基本简介 Dubbo是阿⾥巴巴开源的基于 Java 的⾼性能 RPC分布式服务框架&#xff0c;致⼒于提供⾼性能和透明化的RPC远程服务调⽤⽅案&…