首页 / 资讯中心 / 文章详情

链表双指针技巧:删除倒数节点与两两交换实战

链表双指针技巧:删除倒数节点与两两交换实战 ★ FEATURED ARTICLE
1. 链表双题精讲删除倒数节点与两两交换链表操作一直是算法面试中的高频考点今天我们就来深度剖析两道经典题目LeetCode 19题删除链表的倒数第N个节点和24题两两交换链表中的节点。这两道题分别考察了链表遍历技巧和指针操作基本功掌握它们能帮你解决80%的链表类面试题。提示本文假设读者已经掌握链表的基本结构单链表节点包含val和next指针和基础操作。如果还不熟悉建议先练习简单的链表遍历和增删操作。1.1 题目背景与核心难点19题要求删除链表中倒数第N个节点难点在于如何在一次遍历中找到目标节点。常规思路是先遍历获取链表长度L再定位第L-N1个节点但这需要两次遍历。更优解是使用快慢指针技巧。24题要求两两交换相邻节点例如1-2-3-4变为2-1-4-3。这道题的难点在于指针操作的顺序不能出错否则会导致链表断裂或循环引用。需要特别注意边界条件处理节点数为奇数时最后一个节点保持不变。2. LeetCode 19题删除倒数第N个节点2.1 快慢指针标准解法def removeNthFromEnd(head, n): dummy ListNode(0, head) # 虚拟头节点处理边界情况 fast slow dummy # 快指针先走n步 for _ in range(n): fast fast.next # 同步移动直到快指针到末尾 while fast.next: fast fast.next slow slow.next # 删除目标节点 slow.next slow.next.next return dummy.next关键点解析虚拟头节点dummy node的引入是为了统一处理删除头节点的特殊情况快指针先走n步这样当快指针到达末尾时慢指针正好指向倒数第n个节点的前驱时间复杂度O(L)L为链表长度空间复杂度O(1)2.2 常见错误与调试技巧错误1未处理头节点删除情况# 错误示例当n等于链表长度时这段代码会出错 def removeNthFromEnd(head, n): fast slow head # ...其余代码相同解决方法始终使用虚拟头节点可以避免这种边界条件问题。错误2指针移动步数错误# 错误示例快指针少走一步 for _ in range(n-1): # 应该是range(n) fast fast.next调试技巧在纸上画出链表和指针位置特别是n1和n链表长度的情况使用简单的测试用例验证如[1,2,3], n2 → 应得到[1,3]3. LeetCode 24题两两交换节点3.1 迭代解法详解def swapPairs(head): dummy ListNode(0, head) prev dummy while prev.next and prev.next.next: # 记录当前两个节点 first prev.next second first.next # 执行交换 prev.next second first.next second.next second.next first # 移动prev指针 prev first return dummy.next指针变化过程图示初始状态dummy - 1 - 2 - 3 - 4 第一步prev指向dummy交换1和2 第二步prev指向1原第一个节点交换3和4 最终结果2 - 1 - 4 - 33.2 递归解法实现def swapPairs(head): if not head or not head.next: return head # 要交换的两个节点 first head second head.next # 递归处理剩余部分 first.next swapPairs(second.next) second.next first return second递归调用栈分析swapPairs(1-2-3-4) 2-1-swapPairs(3-4) 2-1-4-33.3 易错点与验证方法常见错误1指针更新顺序错误# 错误示例先断开first.next会导致second丢失 first.next second.next # 错误顺序 prev.next second second.next first常见错误2忽略奇数长度链表测试用例必须包含空链表[]单节点链表[1]偶数长度链表[1,2,3,4]奇数长度链表[1,2,3]可视化调试技巧在纸上画出每步操作前后的指针变化使用printLinkedList函数输出中间状态def printList(node): while node: print(node.val, end-) node node.next print(None)4. 综合应用与进阶思考4.1 两道题的共同技巧虚拟头节点都使用dummy节点简化边界条件处理指针保存在修改指针前先保存必要节点的引用循环条件都需要仔细设计while循环的继续条件4.2 变种题目练习删除倒数第N个节点变种删除倒数第N到第M个节点之间的所有节点找出链表的中间节点快慢指针另一种应用节点交换变种K个一组反转链表LeetCode 25题交换链表中的两个指定节点不需要相邻4.3 性能优化与测试时间复杂度对比题目解法时间复杂度空间复杂度19题快慢指针O(L)O(1)24题迭代O(L)O(1)24题递归O(L)O(L)递归栈压力测试建议构造超长链表测试节点数10^5使用随机生成的链表验证代码鲁棒性对比不同解法在实际运行时的内存消耗5. 手撕代码训练指南5.1 白板编码练习步骤明确问题口头复述题目要求确认理解正确举例说明用具体例子演示输入输出设计算法说出解题思路和关键步骤编写代码边写边解释每个部分的作用测试验证用多个测试用例验证正确性5.2 面试应答策略当面试官提出这两道题时可以这样展示你的思路对于删除倒数第N个节点的问题我首先想到的是快慢指针法。因为常规的两次遍历解法不够高效而快慢指针可以在一次遍历中定位目标节点。需要注意处理删除头节点的特殊情况所以我选择使用虚拟头节点来统一操作逻辑。对于两两交换节点的问题迭代法和递归法都能解决。迭代法的优势是空间复杂度更低而递归法则更简洁。在实际工程中如果链表很长我会优先选择迭代法避免栈溢出。5.3 高频Follow-up问题面试官可能会追问如何修改代码才能返回被删除的节点如果不使用虚拟头节点如何修改代码如何验证链表是否有环快慢指针的另一种应用如何反转整个链表更基础的指针操作练习我在实际面试中遇到过这样的变种题给定一个链表和一个数组数组包含若干个索引要求删除链表中这些索引对应的节点。这道题可以看作是19题的扩展同样需要灵活运用指针操作技巧。
阅读完成 · 觉得有帮助?
咨询建站