ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

LeetCode-Go 题解:24. Swap Nodes in Pairs 两两交换链表中的节点

LeetCode-Go 题解:24. Swap Nodes in Pairs 两两交换链表中的节点 LeetCode-Go 题解24. Swap Nodes in Pairs 两两交换链表中的节点【免费下载链接】LeetCode-Go✅ Solutions to LeetCode by Go, 100% test coverage, runtime beats 100% | LeetCode 题解项目地址: https://gitcode.com/GitHub_Trending/le/LeetCode-Go导读本文基于 LeetCode-Go 仓库中 0024.Swap-Nodes-in-Pairs 官方题解 展开系统讲解 LeetCode 第 24 题「两两交换链表中的节点」的题目约束、核心思路与 Go 语言实现。你将掌握利用哑节点dummy node统一边界处理、借助 Go 多赋值特性在单条语句内完成三个指针的同步交换这一经典技巧并学会如何通过仓库中结构化的测试用例100% 覆盖率验证算法正确性直接可复用于同类型的链表指针操作类题目。题目描述与约束Given a linked list, swap every two adjacent nodes and return its head.You may not modify the values in the lists nodes, only nodes itself may be changed.题目要求对一个单链表每两个相邻节点为一组进行交换并返回交换后的链表头同时有一个硬性约束不允许修改节点内部的 Val 值只能通过调整节点之间的 Next 指针来完成交换。官方示例Given 1-2-3-4, you should return the list as 2-1-4-3.即输入链表1-2-3-4两两交换后输出2-1-4-3。该示例同时隐含了两个关键边界情况链表长度为偶数时全部成对交换若长度为奇数则末尾落单的节点保持原位不动例如1-2-3-4-5应输出2-1-4-3-5。在 LeetCode-Go 仓库中本题对应的完整题目描述同时收录于英文站 content.en 题解 与中文站的 README后者将题意概括为「两两相邻的元素翻转链表」。解题思路哑节点 三指针同步交换原题解给出的思路非常直接——Just follow the problem statement即按照题意逐对处理即可。但实现上有一个值得推敲的细节交换每对节点后链表头部可能发生变化1与2交换后头部变为2如果直接对原始 head 操作就需要单独处理首对节点交换这个特例。为此仓库实现采用了一个经典的工程化技巧引入哑节点dummy node作为哨兵让dummy.Next始终指向链表的真实头部这样无论首对节点是否发生交换最终都只需返回dummy.Next从而把首节点特例统一成普通情况大幅简化代码。核心交换逻辑如下摘自 24. Swap Nodes in Pairs.gofunc swapPairs(head *ListNode) *ListNode { dummy : ListNode{Next: head} for pt : dummy; pt ! nil pt.Next ! nil pt.Next.Next ! nil; { pt, pt.Next, pt.Next.Next, pt.Next.Next.Next pt.Next, pt.Next.Next, pt.Next.Next.Next, pt.Next } return dummy.Next }循环条件的边界语义循环条件pt ! nil pt.Next ! nil pt.Next.Next ! nil保证每次进入循环体时以pt为前驱至少存在两个待交换节点pt.Next即a与pt.Next.Next即b。这一条件天然覆盖了三种终止情形链表为空或只有一个节点条件不成立循环一次都不执行直接返回原链表末尾剩余一个落单节点例如1-2-3-4-5中交换完(1,2)、(3,4)后pt指向4此时pt.Next.Next为nil循环终止节点5保持原位恰好全部成对交换完毕例如1-2-3-4处理完后pt指向4pt.Next为nil循环终止。单行多赋值完成指针重排循环体是本题的精髓所在——利用 Go 语言的多变量同时赋值特性在一条语句中完成四个变量的同步更新pt, pt.Next, pt.Next.Next, pt.Next.Next.Next pt.Next, pt.Next.Next, pt.Next.Next.Next, pt.Next赋值前令a pt.Nextb pt.Next.Nextc pt.Next.Next.Next可能为nil则上式等价于pt b // 前驱前进到 b作为下一对的哑前驱 pt.Next b // a 的 Next 指向 b 的后续 c即 a 与 b 断开 b.Next a // b 指向 a完成本对反转 c 的位置上 // 上一对的后继 c 由 pt.Next.Next.Next 接手接到 b 后面由于多赋值是先统一读取右侧所有表达式的值、再依次写入左侧变量因此pt.Next.Next.Next被写入的并不是交换后的新值而是交换前b的原始后继c这就保证了下一次循环能无缝从c继续不会丢失链表的其余部分。这段实现正是原题解代码见 0024.Swap-Nodes-in-Pairs.md与仓库源码完全一致的版本。复杂度分析时间复杂度O(n)每个节点仅被访问常数次空间复杂度O(1)除哑节点外未使用任何额外存储未递归、未使用辅助数组。ListNode 结构与仓库基础设施代码第一行type ListNode structures.ListNode使用了 Go 的类型别名将仓库公共数据结构 structures.ListNode 引入本题作用域其定义如下type ListNode struct { Val int Next *ListNode }仓库在 structures/ListNode.go 中还提供了两个配套工具函数被测试用例大量复用Ints2List(nums []int) *ListNode将整型切片构造成链表空切片返回nil见 ListNode.goList2Ints(head *ListNode) []int将链表还原为整型切片并内置 100 层深度上限检测一旦超出即 panic提示可能存在环状链表见 ListNode.go。这种切片 ↔ 链表的双向转换约定让 LeetCode-Go 全部链表类题目的输入输出都采用切片形式测试用例因此极其简洁、可读性高。测试用例与验证仓库对本题配备了表驱动测试table-driven tests完整实现见 24. Swap Nodes in Pairs_test.go覆盖了四类关键场景输入链表期望输出覆盖场景[][]空链表边界[1][1]单节点边界[1,2,3,4][2,1,4,3]偶数长度全部成对交换官方示例[1,2,3,4,5][2,1,4,3,5]奇数长度末尾落单节点保持原位测试执行逻辑为structures.Ints2List(p.one)构造链表 → 调用swapPairs→ 用structures.List2Ints还原为切片与期望答案比对同时通过fmt.Printf打印输入输出便于人工核对。该测试文件遵循仓库统一的question24 / para24 / ans24命名约定与 gotest.sh 中go test -covermodeatomic -coverprofilecoverage.txt ./leetcode/...的覆盖测试机制配合支撑起项目「100% test coverage」的承诺——读者在本目录运行go test ./leetcode/0024.Swap-Nodes-in-Pairs/即可复现验证。小结本题是链表指针操作的经典入门题其价值在于两点一是哑节点消除了交换首对节点需特判头指针的分支逻辑使代码在空链表、单节点、奇偶长度等全部边界下保持一致的正确性二是Go 多赋值 指针重排在单条语句内完成a、b的交换与游标前进体现了 Go 语言特性与数据结构操作的巧妙结合。掌握该写法后可顺带迁移到 25. Reverse Nodes in k-Group、92. Reverse Linked List II 等更复杂的链表区间反转题目中。进一步阅读中文题目与题解、英文题解、公共链表结构定义、测试用例。【免费下载链接】LeetCode-Go✅ Solutions to LeetCode by Go, 100% test coverage, runtime beats 100% | LeetCode 题解项目地址: https://gitcode.com/GitHub_Trending/le/LeetCode-Go创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进