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

为什么这道题如此重要

反转链表看似简单,却是链表操作的基石。就像建房子要先打好地基,做复杂的链表操作前必须深刻理解反转原理。无数高频面试题都建立在这个基础之上: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. 整合Sleuth

    Sleuth是 springcloud 分布式跟踪解决方案. Sleuth 术语: 跨度(span ) :Sleuth 的基本工作单元,他用一个64位的id唯一标识.出ID外,span还包含 其他的数 ...

  2. 利用smtp发邮件

    小功能,备忘 MailMessage objMailMessage = new MailMessage();//引入System.Net objMailMessage.From = new MailA ...

  3. MATLAB R2024a免费+破解版本(含密钥)

    强大功能 在使用2024a之前,我一直在使用2018b,最近数学建模+学年论文的摧残,让我看到了matlab新增的强大功能: Deep Learning Toolbox:新增支持 Transforme ...

  4. Qt QTtoolButton 鼠标移动到按钮上时,弹出菜单后,按钮的hover状态无法恢复的问题

    需求:QTtoolButton 鼠标移到按钮上时,弹窗菜单,并且点击菜单或者其他地方,菜单关闭后,按钮的hover状态需要恢复原状. 1. 创建按钮和菜单,并安装事件过滤器 m_Menu = new ...

  5. 洛谷P7911 [CSP-J 2021] 网络连接题解

    普通的模拟题,数据很小,基本排除超时超空间的可能 上代码: #include<bits/stdc++.h> #define LL long long using namespace std ...

  6. PG 实现 Dynamic SQL

    CREATE OR REPLACE FUNCTION public.exec( text) RETURNS SETOF RECORD LANGUAGE 'plpgsql' AS $BODY$ BEGI ...

  7. 【JavaWeb】【Cookie】通过Cookie记录用户上次登陆时间并判断用户是否是首次登陆

    通过Cookie记录用户上次登陆时间并判断用户是否是首次登陆 Cookie类的构造方法 public Cookie(java.lang.String name,java.lang.String ) 1 ...

  8. jenkins异常 -- active (exited),无法启动

    一.问题描述 1.无法启动 systemctl start jenkins 没有反应,没有输出报错 2.查询状态 systemctl status jenkins 3.jenkins拒绝访问 二.解决 ...

  9. HikariCP不断打印WARN日志Failed to validate connection com.mysql.jdbc.JDBC4Connection@xxxxx (...) Possibly consider using a shorter maxLifetime value.

    最终解决方案(结论) maxLifeTime参数需要设置为小于min(数据库的wait_timeout,HA代理的超时时间,其他代理的超时时间);也就是说maxLifeTime不仅要像HikariCP ...

  10. Qt/C++音视频开发60-坐标拾取/按下鼠标获取矩形区域/转换到视频源真实坐标

    一.前言 通过在通道画面上拾取鼠标按下的坐标,然后鼠标移动,直到松开,根据松开的坐标和按下的坐标,绘制一个矩形区域,作为热点或者需要电子放大的区域,拿到这个坐标区域,用途非常多,可以直接将区域中的画面 ...