从生活场景理解链表反转:最重要的基础算法

为什么这道题如此重要

反转链表看似简单,却是链表操作的基石。就像建房子要先打好地基,做复杂的链表操作前必须深刻理解反转原理。无数高频面试题都建立在这个基础之上:K个一组反转链表、判断回文链表、链表重排序等等。真正理解了反转链表,这些题目就会迎刃而解。

问题描述

LeetCode第206题"反转链表"要求:给你单链表的头节点 head,请你反转链表,并返回反转后的链表。

例如:

输入:1 → 2 → 3 → 4 → 5
输出:5 → 4 → 3 → 2 → 1

递归解法:从简单说起

递归法虽然不是最优解,但它的思路最容易理解。想象你在玩多米诺骨牌,先把所有骨牌排好,然后从最后一张开始,一张张往回推。

递归的本质

递归反转的核心思想是:

  1. 先假设子问题已经解决(后面的链表已经反转完成)
  2. 然后解决当前节点如何与已反转部分衔接的问题

就像你要完成一个大项目,不用考虑下属如何完成他们的任务,你只需要考虑如何把大家的工作整合起来。

代码实现和详解

public ListNode reverseList(ListNode head) {
// 基准情况:空链表或只有一个节点时,直接返回
if (head == null || head.next == null) {
return head;
} // 递归反转子链表,获得新的头节点
// 假设后面的链表已经反转完成,newHead指向反转后的头节点
ListNode newHead = reverseList(head.next); // 关键步骤:把当前节点接到反转后链表的末尾
// 假设当前是节点2,head.next是节点3
// head.next.next = head 就是让3指向2
head.next.next = head;
head.next = null; // 断开2原来的指向,防止形成环 return newHead;
}

迭代解法:追求空间最优

迭代法虽然理解起来较难,但它是空间复杂度最优的解法。让我们通过一个生活场景来深入理解。

通过生活场景理解迭代

想象你是一个体操教练,正在教一排学生做"后滚翻"。每个学生原本都面向前方,你要让他们一个接一个地转身。关键是:每处理一个学生时,要确保:

  1. 这个学生不会摔倒(保存next指针)
  2. 他能拉住前一个学生的手(指向prev)
  3. 准备好扶住下一个学生(移动指针)

代码实现和图解

public ListNode reverseList(ListNode head) {
ListNode prev = null; // 已翻转部分的头节点
ListNode curr = head; // 当前正在处理的节点 while (curr != null) {
// 第1步:记住下一个学生,以免等下找不到他
ListNode nextTemp = curr.next; // 第2步:让当前学生转身(改变指针指向)
curr.next = prev; // 第3步:教练和助教往后移动一位
prev = curr; // prev是"助教",扶着已完成转身的学生
curr = nextTemp; // curr是"教练",去帮助下一个学生
} return prev; // prev指向最后一个处理的节点,即新的头节点
}

迭代法的过程图解

以1→2→3→4→5为例:

初始状态:
prev = null, curr = 1
null ← 1 → 2 → 3 → 4 → 5 第一次迭代后:
prev = 1, curr = 2
null ← 1 2 → 3 → 4 → 5 第二次迭代后:
prev = 2, curr = 3
null ← 1 ← 2 3 → 4 → 5 最终状态:
null ← 1 ← 2 ← 3 ← 4 ← 5

深入理解的关键点

1. 指针操作的本质

每次操作都是在改变一个节点的"指向"。就像改变一个人的视线方向,原本看着前方,现在要回头看。

2. 迭代法的不变量

在任何时刻:

  • prev指向的是已完成反转的部分
  • curr指向正在处理的节点
  • nextTemp保存着待处理的部分

3. 为什么需要三个指针

  • prev:没有它,就不知道往哪里指
  • curr:没有它,就不知道现在处理谁
  • nextTemp:没有它,就会断链找不到后续节点

实战应用

这个基础算法在很多场景中都有应用:

  1. 需要倒序处理链表时
  2. 需要判断链表是否回文时
  3. 需要按组反转链表时
  4. 需要重排链表时

小结

掌握链表反转需要:

  1. 理解递归和迭代两种思路的本质
  2. 深入理解指针操作的含义
  3. 反复练习直至形成肌肉记忆
  4. 学会用生活场景类比,加深理解

建议:每天默写一遍这道题,直到闭着眼睛也能写对。因为它是链表操作中最基础也是最关键的操作,掌握了它,其他链表问题都会变得容易很多!


作者:忍者算法

公众号:忍者算法

我准备了一份刷题清单,以及这些题目的详细题解,覆盖了绝大部分常见面试题。我可以很负责任地说,只要你把这些题真正掌握了,80%的算法面试都能遇到相似题目。公众号回复【刷题清单】获取~

【忍者算法】从生活场景理解链表反转:最重要的基础算法|LeetCode第206题 反转链表的更多相关文章

  1. 【算法训练营day4】LeetCode24. 两两交换链表中的结点 LeetCode19. 删除链表的倒数第N个结点 LeetCode面试题 02.07. 链表相交 LeetCode142. 环形链表II

    [算法训练营day4]LeetCode24. 两两交换链表中的结点 LeetCode19. 删除链表的倒数第N个结点 LeetCode面试题 02.07. 链表相交 LeetCode142. 环形链表 ...

  2. 【python】Leetcode每日一题-反转链表 II

    [python]Leetcode每日一题-反转链表 II [题目描述] 给你单链表的头节点 head 和两个整数 left 和 right ,其中 left <= right .请你反转从位置 ...

  3. 【python】Leetcode每日一题-旋转链表

    [python]Leetcode每日一题-旋转链表 [题目描述] 给你一个链表的头节点 head ,旋转链表,将链表每个节点向右移动 k 个位置. 示例1: 输入:head = [1,2,3,4,5] ...

  4. Leetcode 206题 反转链表(Reverse Linked List)Java语言求解

    题目描述: 反转一个单链表. 示例: 输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1->NULL 迭代解 ...

  5. Leetcode(206)-反转链表

    反转一个单链表. 示例: 输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1->NULL 思路:反转链表很简 ...

  6. leetcode每日一题——反转整数

    题目: 反转整数 难度: 简单 描述: 给定一个 32 位有符号整数,将整数中的数字进行反转. 解法: class Solution { public int reverse(int x) { //i ...

  7. [Leetcode] 第148题 排序链表

    一.题目描述 在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序. 示例 1: 输入: 4->2->1->3 输出: 1->2->3->4 示 ...

  8. 【算法】342- JavaScript常用基础算法

    一个算法只是一个把确定的数据结构的输入转化为一个确定的数据结构的输出的function.算法内在的逻辑决定了如何转换. 基础算法 一.排序 1.冒泡排序 //冒泡排序function bubbleSo ...

  9. LeetCode 上最难的链表算法题,没有之一!

    题目来源于 LeetCode 第 23 号问题:合并 K 个排序链表. 该题在 LeetCode 官网上有关于链表的问题中标注为最难的一道题目:难度为 Hard ,通过率在链表 Hard 级别目前最低 ...

  10. 关于dijkstra算法的一点理解

    最近在准备ccf,各种补算法,图的算法基本差不多看了一遍.今天看的是Dijkstra算法,这个算法有点难理解,如果不深入想的话想要搞明白还是不容易的.弄了一个晚自习,先看书大致明白了原理,就根据书上的 ...

随机推荐

  1. README.md书写范例

    具体参考: https://learnku.com/docs/laravel-specification/5.5/readme-examplemd/523

  2. ARTHAS 使用

    1.概述 ARTHAS是阿里巴巴 出品的一款java监控工具,本文介绍以下他的基本使用方法. 2.基本操作 2.1 启动 java -jar arthas-boot.jar 2.2 基础命令 命令 说 ...

  3. 以下哪一项是对CSMA/CA和CSMA/CD LAN控制通用的CSMA方法的适当描述?

    A.   检测载波信号并控制数据传输. B.   获得具有传输权的消息(令牌)的终端传输数据. C.   如果在数据传输过程中发生冲突,立即重新发送. D.   即使在使用传输线时也可以传输数据. = ...

  4. Qt 子窗口 隐藏标题栏的图标,在任务栏上的不显示

    Qt子窗口使用Qt::Dialog样式时,隐藏窗口标题栏图标方法: this->setWindowIcon(QIcon()); Qt子窗口,在任务栏上的不显示,最简单的方法是设置Qt::Tool ...

  5. 通过本地私有的镜像仓库harbor解决网络原因导致的jdk无法加载而造成的docker打包错误

    ​各种网络原因,或是docker.io无法访问,或是阿里的镜像源故障,导致java打包发布的时候报错,很影响代码发布的质量. 解决思路:墙出去把jdk下载下来,代码使用本地的harbor库进行引用,一 ...

  6. 工欲善其事,必先利其器。如何玩转 VS Code?

    Visual Studio Code 作为广受好评的开发工具,已经被越来越多的开发者当作首选的开发工具.然而,你真的了解 VS Code 了吗?你真的会使用 VS Code,把 VS Code 的强大 ...

  7. mysql命令行创建数据库并设置字符集

    CREATE DATABASE test1 DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;

  8. Failed to start bean 'webServerStartStop'; nested exception is org.springframework.beans.FatalBeanException: ServletWebServerFactory implementation

    使用jeecgboot报错 jeecg单测跑不起来,报错如下 Failed to start bean 'webServerStartStop'; nested exception is org.sp ...

  9. Qt编写地图综合应用9-行政区划

    一.前言 行政区划在地图应用中非常有用,行政区划是行政区域划分的简称,是国家为了进行分级管理而实行的区域划分,百度地图提供的内置的函数类支持传入行政区划的名称来获取对应的边界点集合,然后根据该集合来绘 ...

  10. Python 潮流周刊#83:uv 的使用技巧(摘要)

    本周刊由 Python猫 出品,精心筛选国内外的 250+ 信息源,为你挑选最值得分享的文章.教程.开源项目.软件工具.播客和视频.热门话题等内容.愿景:帮助所有读者精进 Python 技术,并增长职 ...