【忍者算法】从生活场景理解链表反转:最重要的基础算法|LeetCode第206题 反转链表
从生活场景理解链表反转:最重要的基础算法
为什么这道题如此重要
反转链表看似简单,却是链表操作的基石。就像建房子要先打好地基,做复杂的链表操作前必须深刻理解反转原理。无数高频面试题都建立在这个基础之上:K个一组反转链表、判断回文链表、链表重排序等等。真正理解了反转链表,这些题目就会迎刃而解。
问题描述
LeetCode第206题"反转链表"要求:给你单链表的头节点 head,请你反转链表,并返回反转后的链表。
例如:
输入:1 → 2 → 3 → 4 → 5
输出:5 → 4 → 3 → 2 → 1
递归解法:从简单说起
递归法虽然不是最优解,但它的思路最容易理解。想象你在玩多米诺骨牌,先把所有骨牌排好,然后从最后一张开始,一张张往回推。
递归的本质
递归反转的核心思想是:
- 先假设子问题已经解决(后面的链表已经反转完成)
- 然后解决当前节点如何与已反转部分衔接的问题
就像你要完成一个大项目,不用考虑下属如何完成他们的任务,你只需要考虑如何把大家的工作整合起来。
代码实现和详解
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;
}
迭代解法:追求空间最优
迭代法虽然理解起来较难,但它是空间复杂度最优的解法。让我们通过一个生活场景来深入理解。
通过生活场景理解迭代
想象你是一个体操教练,正在教一排学生做"后滚翻"。每个学生原本都面向前方,你要让他们一个接一个地转身。关键是:每处理一个学生时,要确保:
- 这个学生不会摔倒(保存next指针)
- 他能拉住前一个学生的手(指向prev)
- 准备好扶住下一个学生(移动指针)
代码实现和图解
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:没有它,就会断链找不到后续节点
实战应用
这个基础算法在很多场景中都有应用:
- 需要倒序处理链表时
- 需要判断链表是否回文时
- 需要按组反转链表时
- 需要重排链表时
小结
掌握链表反转需要:
- 理解递归和迭代两种思路的本质
- 深入理解指针操作的含义
- 反复练习直至形成肌肉记忆
- 学会用生活场景类比,加深理解
建议:每天默写一遍这道题,直到闭着眼睛也能写对。因为它是链表操作中最基础也是最关键的操作,掌握了它,其他链表问题都会变得容易很多!
作者:忍者算法
公众号:忍者算法
我准备了一份刷题清单,以及这些题目的详细题解,覆盖了绝大部分常见面试题。我可以很负责任地说,只要你把这些题真正掌握了,80%的算法面试都能遇到相似题目。公众号回复【刷题清单】获取~
【忍者算法】从生活场景理解链表反转:最重要的基础算法|LeetCode第206题 反转链表的更多相关文章
- 【算法训练营day4】LeetCode24. 两两交换链表中的结点 LeetCode19. 删除链表的倒数第N个结点 LeetCode面试题 02.07. 链表相交 LeetCode142. 环形链表II
[算法训练营day4]LeetCode24. 两两交换链表中的结点 LeetCode19. 删除链表的倒数第N个结点 LeetCode面试题 02.07. 链表相交 LeetCode142. 环形链表 ...
- 【python】Leetcode每日一题-反转链表 II
[python]Leetcode每日一题-反转链表 II [题目描述] 给你单链表的头节点 head 和两个整数 left 和 right ,其中 left <= right .请你反转从位置 ...
- 【python】Leetcode每日一题-旋转链表
[python]Leetcode每日一题-旋转链表 [题目描述] 给你一个链表的头节点 head ,旋转链表,将链表每个节点向右移动 k 个位置. 示例1: 输入:head = [1,2,3,4,5] ...
- Leetcode 206题 反转链表(Reverse Linked List)Java语言求解
题目描述: 反转一个单链表. 示例: 输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1->NULL 迭代解 ...
- Leetcode(206)-反转链表
反转一个单链表. 示例: 输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1->NULL 思路:反转链表很简 ...
- leetcode每日一题——反转整数
题目: 反转整数 难度: 简单 描述: 给定一个 32 位有符号整数,将整数中的数字进行反转. 解法: class Solution { public int reverse(int x) { //i ...
- [Leetcode] 第148题 排序链表
一.题目描述 在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序. 示例 1: 输入: 4->2->1->3 输出: 1->2->3->4 示 ...
- 【算法】342- JavaScript常用基础算法
一个算法只是一个把确定的数据结构的输入转化为一个确定的数据结构的输出的function.算法内在的逻辑决定了如何转换. 基础算法 一.排序 1.冒泡排序 //冒泡排序function bubbleSo ...
- LeetCode 上最难的链表算法题,没有之一!
题目来源于 LeetCode 第 23 号问题:合并 K 个排序链表. 该题在 LeetCode 官网上有关于链表的问题中标注为最难的一道题目:难度为 Hard ,通过率在链表 Hard 级别目前最低 ...
- 关于dijkstra算法的一点理解
最近在准备ccf,各种补算法,图的算法基本差不多看了一遍.今天看的是Dijkstra算法,这个算法有点难理解,如果不深入想的话想要搞明白还是不容易的.弄了一个晚自习,先看书大致明白了原理,就根据书上的 ...
随机推荐
- 【C++】关于 Visual Studio 的使用技巧(保姆级教程)
目录 fliter 视图 输出文件位置设置 查看预处理结果 将目标文件转换为可读的汇编 自定义程序入口 调试时查看变量在内存中的具体值 查看代码的反汇编 fliter 视图 visual studio ...
- AE错误代码
错误代码 错误描述 错误名称 HRESULT:0x80040201 "Failed to load a resource (string, icon, bitmap, etc)." ...
- 【双堆懒删除】codeforces 1294 D. MEX maximizing
前言 双堆懒删除 当需要维护若干元素中的最大值(或最小值)时,可以用一个堆维护,但是堆只擅长处理堆顶元素,对堆中任意元素的处理就束手无策了.此时,可以引入另外一个堆,我们定义原来的堆为保存堆 \(ex ...
- COSBrowser文件编辑-随时随地在线编辑
本文介绍如何通过COSBrowser文件在线编辑功能更方便的使用云上存储的数据. 痛点分析 日常工作和生活中,我们需要把记录的文档.编写的文案.音视频文件保存管理好,又担心设备损坏.文件丢失或是更换设 ...
- vue3笔记 - 父子组件通信
父传子 说明:父组件将数据绑定在组件标签上:子组件props接收 父组件: <template> <Child :msg="msg" /> </tem ...
- 加入security+jwt安全策略
Pom中引入 <!-- security --> <dependency> <groupId>org.springframework.boot</groupI ...
- Qt编写linux上视频流播放器(支持海康大华宇视等各种网络摄像机)
一.前言 在windows上的视频流播放器有很多,而且各个监控厂家无论大厂还是小厂,基本上都提供了客户端,甚至很多第三方的监控平台软件厂商,也都提供了windows的版本,基本的都没有提供linux版 ...
- Qt数据库应用4-数据打印到纸张
一.前言 数据能够打印到pdf文件,当然可以打印到纸张,而且使用qprinter默认就是打印到纸张的,上一篇文章写得功能是打印到pdf,其实还要单独特殊设置打印到文件,并指定格式为pdf.不指定输出文 ...
- Qt编写的项目作品8-视频综合应用示例
一.功能特点 1.1 基础功能 支持各种音频视频文件格式,比如mp3.wav.mp4.asf.rm.rmvb.mkv等. 支持本地摄像头设备,可指定分辨率.帧率. 支持各种视频流格式,比如rtp.rt ...
- Qt编写安防视频监控系统58-子模块2窗口信息
一.前言 窗口信息一般用来打印输出文字信息,带时间,有些用户场景可能除了时间和内容以外,还需要其他的字段信息,可以自行在代码中增加字段即可,窗口信息一般以表格样式居多,上面是字段标题,下面是一行行的输 ...