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

关于《算法25. K 个一组翻转链表》的解题思路

《25. K 个一组翻转链表》的解法:

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
# 需要理解变量指向节点和节点指向节点(.next)的区别
class Solution:def reverseKGroup(self, head: Optional[ListNode], k: int) -> Optional[ListNode]:# 统计节点数n = 0cur = headwhile cur:n+=1cur=cur.next# 指向头节点的哑节点p0 = dummy =ListNode(next=head)# 引用前一个节点的变量pre = None# 引用当前节点的变量cur = head# k个一组处理while n>=k:n-=k# 反转k个节点的链表# 依次遍历只改变一个节点的指向for _ in range(k):# nxt指向cur的下一个变量nxt = cur.next# cur指向的节点的下一个节点指向prevcur.next = pre# 变量引用位置往前推进# pre 是这组反转后的新头节点pre = cur# cur 是下一组的开始cur = nxt# 反转k个节点链表之后,需要把反转后的链表与没有反转的链表联接起来# 未反转前的头节点,现在是尾节点nxt = p0.next # 反转后的尾节点和未反转的头节点联接起来nxt.next = cur# p0指向新的头节点p0.next = pre# p0移动到最新反转的链表的尾节点,为什么不指向新链表的头节点,可以类比最开始p0指向的是Nonep0 = nxtreturn dummy.next 

我反转了k个节点,但是不知道怎么往后推近,上面代码是怎么能想到的呢

已经理解了如何反转一个长度为 k 的链表子段,但卡在了如何把反转后的子段重新连接回原链表,并推进到下一组。我们来一步步拆解你这段代码的思路,特别是那个“灵光一闪”的关键点:p0 = dummyp0.next 的作用。


🌟 核心思想:用一个“前驱指针” p0 来维护上一组的尾节点

我们希望:

  • 每次反转完一个 k 长度的子链表后,把这个反转后的子链表接回原链表。
  • 然后移动到下一组继续处理。

难点在于:反转后,原来的头变成尾,原来的尾变成头,你怎么知道该把谁接到谁身上?

🔍 举个例子:

原链表:1 -> 2 -> 3 -> 4 -> 5,k = 2
第一组:1 -> 2 反转后变成 2 -> 1
我们要把 2 接到前面(比如 dummy),然后把 1 指向 3

所以需要一个指针记住“上一组的尾节点”,也就是下一组反转后要接在它后面。


🧠 关键变量解析

p0 = dummy = ListNode(next=head)
pre = None
cur = head
  • dummy: 虚拟头节点,防止头节点被修改。
  • p0: 上一组的尾节点,也是当前组的前驱节点。
    👉 所以当前这组反转完之后,要让 p0.next 指向反转后的新头节点

比如刚开始:

dummy -> 1 -> 2 -> 3 -> ...p0cur

🔁 处理每一组 k 个节点

while n >= k:n -= kfor _ in range(k):nxt = cur.nextcur.next = prepre = curcur = nxt

这段完成了对 k 个节点的反转。此时:

  • pre 是这组反转后的新头节点(原尾节点)
  • cur 是下一组的开始(或 None)
  • pre 到原来的 cur 之间的链表已被反转

比如反转 1->2 后:

pre: 2 -> 1    (1.next 指向 None?不对,其实还没连好!)
cur: 指向 3
但 1.next 还是指向 None?怎么连回去?

这时候你发现:我们只是局部反转了,但没有和前后连接!


🧩 神来之笔:连接反转后的子链表

nxt = p0.next
nxt.next = cur
p0.next = pre
p0 = nxt

我们逐行分析:

1. nxt = p0.next

  • p0.next 是当前这组的原始头节点(反转前)
  • 反转后它变成了尾节点
  • 我们要记住它,因为下一组要接在它后面!

👉 所以 nxt 就是当前组反转后的尾节点

2. nxt.next = cur

  • 把当前组的尾节点(nxt)指向 cur(下一组的开头)
  • 这样就完成了“当前组”和“剩余链表”的连接!

比如:

反转后:2 -> 1   (1.next 还没连)
cur 指向 3
现在让 1.next = 3

✅ 链表变成:2 -> 1 -> 3 -> 4 -> ...

3. p0.next = pre

  • p0 是上一组的尾节点
  • pre 是当前组反转后的头节点(比如 2)
  • 所以 p0.next = pre 就是把上一组连到当前组

比如:

dummy -> 2 -> 1 -> 3 -> ...

4. p0 = nxt

  • p0 移动到当前组的尾节点(也就是 nxt
  • 因为下一次反转后,还要把下下组接在它后面!

👉 所以 p0 始终是“上一组的尾节点”,也就是下一组的前驱


🔄 下一轮迭代

继续处理下一组 k 个节点,重复上述过程。


✅ 总结:为什么能想到 p0

思考过程对应代码
反转后,怎么把新链表接回去?需要一个指针记住“前驱”
前驱是谁?是上一组的尾节点p0 就是这个角色
反转后,原来的头变成尾,要让它指向下一组nxt = p0.next(原头)→ nxt.next = cur
反转后的头是 pre,要让前驱指向它p0.next = pre
更新 p0 到当前组尾,为下一组做准备p0 = nxt

🎯 类比:穿珠子

想象你在穿珠子,每 k 个一组反转顺序:

  • p0 是你左手拿着的“最后一个穿好的珠子”
  • 你右手把接下来 k 个珠子反转
  • 然后左手的珠子连到这组的新开头
  • 最后,你把这组的最后一个珠子拿在左手里,继续下一轮

💡 小技巧记忆

记住三步:

  1. 保存当前组的头nxt = p0.next(反转后它变成尾)
  2. 反转 k 个节点pre, cur 搞定
  3. 连接
    • nxt.next = cur # 尾接下一组
    • p0.next = pre # 前驱接新头
    • p0 = nxt # 更新前驱为当前尾

✅ 最后:你的困惑解决了没?

你说:“我反转了 k 个节点,但不知道怎么往后推进。”

答案就是:p0 记住上一组的尾,每次反转完,用 p0.next = pre 接上,再把 p0 移到当前组尾(nxt)继续。

这就是“推进”的关键!


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

相关文章:

  • ESP32入门开发·通用硬件定时器 (GPTimer)
  • 【Linux】15. 详解Vim快捷操作
  • Flask ORM 查询详解:Model.query vs db.session.query vs db.session.execute
  • Java Socket 基础教程
  • 新手入门 Makefile:FPGA 项目实战教程(一)
  • pnpm常用命令;为什么使用pnpm?
  • 古中医学习笔记专题文章导航
  • 【STM32入门教程】stm32简介
  • 基于 NVIDIA 生态的 Dynamo 风格分布式 LLM 推理架构
  • Kotlin Data Classes 快速上手
  • SwiftUI 页面弹窗操作
  • Windows批处理脚本自动合并当前目录下由You-get下载的未合并的音视频文件
  • Polyak-Ruppert 平均
  • UCLAMP3311T.TCT TVS二极管阵列 Semtech升特半导体 集成电路IC
  • tp5集成elasticsearch笔记
  • 20. 了解过尾递归优化吗
  • ASCII与Unicode:编码世界的奥秘
  • TLS 终止在真实业务中的防护价值
  • 36 C++ STL模板库5-string
  • Python网络爬虫(二) - 解析静态网页
  • IPTV系统:开启视听与管理的全新篇章
  • CMake 如何查找 Python2和Python3
  • 利用 Python 爬虫按图搜索 1688 商品(拍立淘)实战指南
  • 17. 如何判断一个对象是不是数组
  • 肖臻《区块链技术与应用》第十一讲:比特币核心概念重温:一文读懂私钥、交易、挖矿与网络现状
  • Redis7学习——Redis的十大类型String、List、Hash、Set、Zset
  • 解决:Gazebo连接模型数据库失败
  • linux 内核 - 内存管理概念
  • Apifox精准定义复杂API参数结构(oneOf/anyOf/allOf)
  • aave v3 存款与借款利息的计算方式