当前位置: 首页 > news >正文

LeetCode hot 100 每日一题(18)——206.反转链表

迭代算法

class Solution {public ListNode reverseList(ListNode head) {// 如果链表为空 或者只有一个节点,直接返回即可if (head == null || head.next == null) {return head;}// 定义三个指针ListNode pre = null;      // pre 指向当前节点的前一个节点(初始时为 null)ListNode cur = head;      // cur 指向当前处理的节点(初始时是 head)ListNode next = head.next; // next 指向 cur 的下一个节点,防止链表断开// 遍历整个链表while (cur != null) {// 1. 断开并反转:让当前节点指向前一个节点cur.next = pre;// 2. 移动 pre 到 cur 位置(相当于前进一格)pre = cur;// 3. 移动 cur 到 next(继续处理下一个节点)cur = next;// 4. 更新 next 指针(如果 cur 不是 null,就让 next 前进一格)if (next != null) {next = next.next;}}// 最终 pre 指向新链表的头结点return pre;}
}

图解说明(以链表 1 → 2 → 3 → 4 → 5 为例)

初始状态:

pre = null 
cur = 1 
next = 2 
链表: 1 → 2 → 3 → 4 → 5
第一次循环:

cur.next = pre → 让 1 指向 null
pre = cur → pre 移动到 1
cur = next → cur 移动到 2
next = next.next → next 移动到 3

pre = 1 → null 
cur = 2 
next = 3 
链表断开后局部: 1 → null 剩余: 2 → 3 → 4 → 5
第二次循环:

cur.next = pre → 让 2 指向 1
pre = cur → pre 移动到 2
cur = next → cur 移动到 3
next = next.next → next 移动到 4

pre = 2 → 1 → null 
cur = 3 
next = 4 
链表断开后局部: 2 → 1 → null 
剩余: 3 → 4 → 5`
第三次循环:
pre = 3 → 2 → 1 → null 
cur = 4 
next = 5
第四次循环:
pre = 4 → 3 → 2 → 1 → null 
cur = 5 
next = null
第五次循环:
pre = 5 → 4 → 3 → 2 → 1 → null 
cur = null   // 结束

最终返回 pre,即新的头结点 5

  • pre 负责记录“反转好的部分”;

  • cur 负责扫描链表;

  • next 保证链表不会断裂。

整个过程就像不断地把“火车车厢”从前面摘下来,挂到新的链表头部。

难以理解的是,cur.next = pre可以让链表断开,随后三个指针依次向后移动即可

递归解法

递归实现反转链表常常用来考察递归思想,这里就用纯递归来翻转链表。

具体来说,我们的 reverse 函数定义是这样的:

输入一个节点 head,将「以 head 为起点」的链表反转,并返回反转之后的头结点

/*** Definition for singly-linked list.* public class ListNode {*     int val;*     ListNode next;*     ListNode() {}*     ListNode(int val) { this.val = val; }*     ListNode(int val, ListNode next) { this.val = val; this.next = next; }* }*/
class Solution {public ListNode reverseList(ListNode head) {// ① 递归的终止条件://    当链表为空(head == null)或只剩一个节点(head.next == null)时,//    这个节点本身就是反转后的头节点,直接返回它。if (head == null || head.next == null) {return head;}// ② 递归处理子问题://    反转以 head.next 为头的“子链表”,//    递归返回值 last 是整个子链表反转后的新头(也就是原来的尾)。ListNode last = reverseList(head.next);// ③ 回溯阶段指针翻转(关键两步中的第一步)://    此时 head.next 指向“子链表反转后的尾结点前的那个结点”(原来的 head.next),//    让该结点的 next 指回 head,把 head 接到子链表的末尾。head.next.next = head;// ④ 断开旧的指向(关键两步中的第二步)://    原来 head -> head.next 的旧边需要置空,否则会形成环。head.next = null;// ⑤ 返回整条链反转后的头结点://    始终是递归返回的 last。return last;}
}

图解

原始链表
在这里插入图片描述

ListNode last = reverse(head.next);

在这里插入图片描述

执行reverse后变成以下:
在这里插入图片描述

head.next.next = head;

在这里插入图片描述

head.next = null;
return last;

原来 head -> head.next 的旧边需要置空,否则会形成环。
在这里插入图片描述

链表反转完成!

其余事项

力扣题解前的注释:

/*** Definition for singly-linked list.* public class ListNode {*     int val;*     ListNode next;*     ListNode() {}*     ListNode(int val) { this.val = val; }*     ListNode(int val, ListNode next) { this.val = val; this.next = next; }* }*/
  • public class ListNode { ... }
    定义了一个叫 ListNode 的类,每个对象就是链表中的一个节点。

  • int val;
    节点存储的 (比如链表里 1、2、3 就存在这里)。

  • ListNode next;
    指向 下一个节点 的引用。如果是链表的最后一个节点,它的 next 就是 null

接下来是三个 构造方法(方便创建不同情况的节点):

  • ListNode() {}
    空构造器,创建一个值为默认值(0),且没有下一个节点的对象。
    (几乎用不到,但保留了。)

  • ListNode(int val) { this.val = val; }
    创建一个只带值的节点,比如:

    ListNode node = new ListNode(5); // val = 5, next = null

  • ListNode(int val, ListNode next) { this.val = val; this.next = next; }
    创建一个带值、同时直接指定下一个节点的对象,比如:

    ListNode node2 = new ListNode(2); ListNode node1 = new ListNode(1, node2); // node1 -> node2

http://www.dtcms.com/a/353086.html

相关文章:

  • 开源 | 推荐一套企业级开源AI人工智能训练推理平台(数算岛):完整代码包含多租户、分布式训练、模型市场、多框架支持、边缘端适配、云边协同协议:
  • 高并发写入、毫秒级查询——盘古信息携手 TDengine 时序数据库解决六大技术挑战
  • SimLab Composer8.2_win中文_3D绘画_安装教程
  • 音频时长裁剪工具:高效处理音频,让内容创作更轻松
  • 【Rust】 2. 数据类型笔记
  • Compose副作用域
  • 大模型重构建筑“能耗基因“:企业如何用物联中台打响能源革命?
  • 入行IC | 数字IC设计和FPGA哪个好?
  • STM32 入门实录:从 0 到 3 色 LED 呼吸式闪烁
  • Git-远程操作
  • 基于 Node.js 的淘宝 API 接口开发:快速构建异步数据采集服务
  • SFTP服务器可以通过同一个登录到SFTP服务器的账号密码连接上控制台吗
  • 【0420】Postgres内核 实现(借助 SMgrRelation)为指定 table(CREATE TABLE)创建 disk file
  • android证书相关
  • 天启录:Linux性能调优·混沌掌控者篇
  • Android中AAR、JAR文件
  • 具身导航助力果园种植!基于模仿学习的果园环境无人机视觉导航
  • Spring Boot项目集成日志系统使用完整指南
  • R-Zero:通过自博弈机制让大语言模型无需外部数据实现自我进化训练
  • Flutter桌面应用实战:Windows系统代理切换工具开发
  • 集成电路学习:什么是SSD单发多框检测器
  • 线性回归原理推导与应用(十一):多重共线性
  • 20250827的学习笔记
  • Kubernetes(k8s) 常用命令
  • 从零开始学习JavaWeb-19
  • 解决跨运营商限速:在飞牛OS系统上启用BBR算法优化网络速度
  • 数据结构:单链表的应用(力扣算法题)第一章
  • 腾讯云人脸识别API技术深度解析:从算法原理到工程实践
  • Diagnosing bias and variance|诊断偏差和方差
  • 文件系统中的核心数据结构