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

力扣 Hot 100 之 206. 反转链表:面试官的“开胃菜”

206. 反转链表这道题在链表界的地位,大约等同于编程语言里的 Hello World。

虽然它是简单题,但据我观察,能一遍 bug free且能清晰讲出递归逻辑的人,其实并没有想象中那么多。很多人脑子会了,手一写,NPE(空指针)了,或者链表断了。

今天咱们就来彻底搞定它,顺便聊聊怎么在面试里把这道题写出“花”来。

题目是个啥?

给你一个单链表的头节点head,请你反转链表,并返回反转后的头节点。

输入:1 -> 2 -> 3 -> 4 -> 5 -> NULL

输出:5 -> 4 -> 3 -> 2 -> 1 -> NULL

看着简单吧?不就是把箭头调个头吗?

嘿,链表这东西最烦人的就是:由于它是单向的,你一旦回头,就找不到前任了;一旦往前走,就找不到后路了。 所以,操作指针的时候得格外小心。


策略一:双指针迭代法

这是最推荐的面试写法。逻辑清晰,空间复杂度 O(1),不容易出错。

核心心法:三人行

虽然叫双指针,但其实我们需要三个变量来玩转这场“移形换影”:

  1. curr(当前节点):我现在在哪。

  2. prev(前驱节点):我要把箭头指给谁(我的新后继)。

  3. next(临时节点):最重要的备胎。在我改变心意指向prev之前,我得先记下来我原本要去哪,不然一断链,后面的节点全丢了。

动图脑补流程

想象一下,你站在curr(比如节点 2) 的位置:

  1. 备份:先把curr.next(节点 3) 存到next变量里。(防丢失)

  2. 掉头:把curr.next指向prev(节点 1)。(关键一步,链子反了)

  3. 挪窝

    • prev往前走一步,变成curr

    • curr往前走一步,变成刚才备份的next

class Solution { public ListNode reverseList(ListNode head) { // prev 初始化为 null,因为反转后,原本的头节点要指向 null ListNode prev = null; ListNode curr = head; while (curr != null) { // 1. 记下原本的下一步去哪(保存现场) ListNode nextTemp = curr.next; // 2. 斩断情丝,回首掏(指针反转) curr.next = prev; // 3. 整体向后移动 prev = curr; curr = nextTemp; } // 循环结束时,curr 是 null,prev 才是新的头节点(原本的尾巴) return prev; } }

防坑指南:

  • 千万别忘了最后返回的是prev,不是curr(循环结束时curr已经是null了)。

  • 别忘了初始化prev = null,否则反转后的尾巴没法结束。


策略二:递归法

如果你想在面试官面前秀一下你的抽象思维能力,或者想让代码看起来短小精悍,可以用递归。

但说实话,这玩意儿非常绕,脑子不好使的时候容易把自己绕进去。

核心心法:甩锅

递归的精髓在于信任。

假设我们有一个函数 reverseList(head),它的作用是把以 head 为头的链表反转,并返回新的头。

面对1 -> 2 -> 3 -> 4 -> 5

  1. 我(节点 1)想反转整个链表。

  2. 我太懒了,我先对 head.next(也就是节点 2)说:“兄弟,你带着后面那帮人先去反转一下。”

    ListNode newHead = reverseList(head.next);

  3. 假设第 2 步成功了,现在的局面是:

    1 -> 2 <- 3 <- 4 <- 5

    注意:此时 1 还连着 2,但 2 已经是后面那串反转后的链表的“尾巴”了。

  4. 关键操作:我要让 2 指回 1。

    head.next.next = head; (翻译:我下家的下家,变成我自己)

  5. 断后路:1 现在是新的尾巴了,必须指向 null,否则就死循环了。

    head.next = null;

class Solution { public ListNode reverseList(ListNode head) { // 递归终止条件:链表为空,或者只有一个节点,那还反转个屁,直接返回 if (head == null || head.next == null) { return head; } // 1. 甩锅:先让后面的节点去反转 // newHead 只是为了最后返回用,中间过程完全不碰它 ListNode newHead = reverseList(head.next); // 2. 关键:把当前节点挂到后面那串链表的尾巴上 // head.next 此时就是后面那串的尾节点 head.next.next = head; // 3. 断开原来的连接,防止环路 head.next = null; return newHead; } }

优缺点分析:

  • :代码行数少,逻辑看起来很高级。

  • :空间复杂度是 O(N),因为要压栈。如果链表非常长,可能会StackOverflow。在工程项目里,还是老老实实写迭代法吧,别搞这些花里胡哨的。


总结

反转链表这道题,属于**“肌肉记忆”**级别的题目。

  • 面试求稳:写迭代法(双指针),解释清楚prev,curr,next的作用。

  • 面试求异:如果面试官问“能不能用递归”,你再反手甩出第二种解法,并顺便聊聊递归栈的深度问题,B 格瞬间拉满。

最后,记住这句话:操作链表前,先把next存起来,不然链表断了,神仙也救不回来。

去刷题吧,祝大家都能把 offer 拿到手软!

http://www.cnnetsun.cn/news/53188.html

相关文章:

  • 入门大模型必知的100个基础问题(附简明答案)
  • vue基于Spring Boot的建筑材料管理系统的应用和研究_ug8y52z3
  • 【大模型】-LangChain--RAG文档系统
  • 探索非线性电液伺服系统的模型自适应反步控制
  • 降AI率就要牺牲文笔?WriterPro第一个不服!实测对比比原文写得还好,这文笔简直绝了
  • 我不是这样
  • 10.8 总结
  • 列车售票|基于springboot 列车售票系统(源码+数据库+文档)
  • AI驱动的手动测试变革:赋能而非替代
  • 【奶茶Beta专项】【LVGL9.4源码分析】09-core-group
  • 网络安全异想天开(不定期更新)
  • 《CAPL脚本实现CANOE工具 Bus-Off自动恢复(含重试机制)》
  • 力扣1965-丢失信息的雇员
  • Flutter 测试全栈指南:从单元测试到黄金路径验证的工程化实践
  • EtherCAT 逐帧报文解析:配置SM/FMMU
  • Springboot连锁火锅店餐饮管理系统h2dg0(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
  • Windows系统文件wavemsp.dll丢失或损坏的问题 下载修复
  • Windows系统文件wdi.dll缺失或损坏问题 下载修复
  • 基于风险演进的智能测试策略设计
  • 论文查重焦虑成流量密码?虎贲等考 AI 直接用免费模式,打破行业游戏规则
  • vue基于Spring Boot的高职院校贫困生困难生智慧关爱系统的开发_f0txl8vu
  • AI 写论文哪家强?虎贲等考 AI!毕业论文全链路 “超级哇塞”,开题到答辩一路开挂~
  • Coze平台指南(1):coze平台概览与测试应用展望
  • 生物识别系统的测试安全性与漏洞防护实践
  • 我终于停止写 JUnit 了!用 JavaParser + GPT-4 自动生成 90% 覆盖率的单元测试
  • 源码读不下去?阿里架构师教你“三步走”阅读法,彻底告别“打开源码就犯困”
  • 大梵公考:国考省考每一年的岗位一样吗?
  • 大梵公考:国考和省考二选一怎么选?
  • Java中如何检测死锁?如何预防和避免线程死锁?
  • Day32 类的定义和方法