LeetCode链表题核心技巧:翻转、旋转与去重实战
2026/8/10 11:41:44 网站建设 项目流程

1. LeetCode链表题核心知识点解析

作为程序员面试的"金标准",LeetCode上的链表问题一直是算法考察的重点。今天我想结合25题(K个一组翻转链表)、61题(旋转链表)和82题(删除排序链表中的重复元素II)这三道经典题目,分享链表操作的核心技巧和实战心得。这三道题看似简单,但实际涵盖了链表处理的三大核心操作:翻转、旋转和去重,掌握它们就能解决80%的链表类问题。

我刷题时发现,很多初学者容易在这些题目上翻车,不是因为算法有多难,而是对链表的基础操作不够熟练。比如翻转链表时指针丢失、旋转链表时成环、删除节点时边界条件处理不当等问题屡见不鲜。下面我就结合具体代码,拆解每个操作的关键步骤和易错点。

2. 题目25:K个一组翻转链表(Hard)

2.1 问题描述与核心思路

给定一个链表,每k个节点一组进行翻转,返回翻转后的链表。如果节点总数不是k的整数倍,最后剩余的节点保持原有顺序。k是一个正整数且小于或等于链表长度。

这道题的难点在于如何高效地处理分组翻转和组间连接。我的解决思路是:

  1. 先实现单次翻转k个节点的子函数
  2. 遍历链表时维护四个关键指针:
    • pre:当前组的前驱节点
    • start:当前组的起始节点
    • end:当前组的结束节点
    • next:下一组的起始节点

关键提示:在翻转前必须先保存next指针,否则链表会断开丢失后续节点

2.2 完整代码实现与逐行解析

def reverseKGroup(head, k): dummy = ListNode(0) dummy.next = head pre = dummy while head: # 定位当前组的end节点 end = pre for _ in range(k): end = end.next if not end: # 不足k个直接返回 return dummy.next # 保存关键节点指针 next_group = end.next start = pre.next # 断开当前组与后续连接 end.next = None # 翻转当前组并重新连接 pre.next = self.reverse(start) start.next = next_group # 移动指针到下一组 pre = start head = next_group return dummy.next def reverse(self, head): prev = None curr = head while curr: next_node = curr.next curr.next = prev prev = curr curr = next_node return prev

代码中的几个关键点:

  1. 使用dummy节点简化头节点处理
  2. 内层循环定位end节点时,如果遇到None直接返回(不足k个)
  3. 翻转前必须断开当前组与后续的连接(end.next = None)
  4. 翻转后重新连接时,原start节点变成组尾,需连接next_group

2.3 边界条件与易错点

在实际编码中,我踩过以下几个坑:

  1. 指针丢失:翻转前未保存next_group指针,导致链表断裂
  2. 组间连接错误:翻转后忘记将start.next指向next_group
  3. k=1的情况:需要特殊处理,否则会有不必要的翻转操作
  4. 空链表处理:需要在一开始检查head是否为None

测试用例设计建议:

  • 常规情况:1->2->3->4->5, k=2/3
  • 边界情况:空链表,k=1,k等于链表长度
  • 异常情况:k=0(题目已约束k为正整数)

3. 题目61:旋转链表(Medium)

3.1 问题分析与解法优化

给定一个链表的头节点head,将链表每个节点向右移动k个位置。例如: 输入:1->2->3->4->5->NULL, k=2 输出:4->5->1->2->3->NULL

这道题的关键在于认识到:旋转k次等价于将链表后k%len个节点移动到前面。我的优化解法步骤如下:

  1. 计算链表长度len,并找到尾节点tail
  2. 计算有效旋转次数k = k % len
  3. 定位新的尾节点new_tail,它在第len - k个位置
  4. 重组链表:
    • new_head = new_tail.next
    • new_tail.next = None
    • tail.next = head

3.2 代码实现与性能考量

def rotateRight(head, k): if not head or k == 0: return head # 计算链表长度并获取尾节点 curr = head length = 1 while curr.next: curr = curr.next length += 1 tail = curr # 计算有效旋转次数 k = k % length if k == 0: return head # 定位新的尾节点 new_tail = head for _ in range(length - k - 1): new_tail = new_tail.next # 重组链表 new_head = new_tail.next new_tail.next = None tail.next = head return new_head

时间复杂度分析:

  1. 计算长度:O(n)
  2. 定位新尾节点:O(n-k) 总体时间复杂度为O(n),空间复杂度O(1)

3.3 常见错误与调试技巧

我在实践中遇到的典型错误包括:

  1. 成环问题:忘记断开new_tail.next,导致链表成环
  2. k大于长度:未处理k % length,导致无效遍历
  3. 空指针:对空链表或k=0的情况未做检查

调试技巧:

  • 打印关键节点的值:如tail.val, new_tail.val
  • 可视化链表:用箭头表示指针关系
  • 小数据量测试:如长度为1或2的链表

4. 题目82:删除排序链表中的重复元素II(Medium)

4.1 双指针解法精讲

给定一个已排序的链表,删除所有含有重复数字的节点,只保留原始链表中没有重复出现的数字。例如: 输入:1->2->3->3->4->4->5 输出:1->2->5

这道题的关键在于如何处理连续重复的节点。我的解法使用双指针:

  1. dummy节点:处理头节点可能被删除的情况
  2. pre指针:指向当前确定不重复的节点
  3. curr指针:用于遍历和检测重复

4.2 代码实现与逻辑拆解

def deleteDuplicates(head): dummy = ListNode(0) dummy.next = head pre = dummy curr = head while curr: # 发现重复节点 if curr.next and curr.val == curr.next.val: # 跳过所有重复节点 while curr.next and curr.val == curr.next.val: curr = curr.next # 删除重复节点 pre.next = curr.next else: pre = pre.next curr = curr.next return dummy.next

关键逻辑说明:

  1. 当发现curr与下一节点值相同时,进入重复处理流程
  2. 内层while循环跳过所有相同值的节点
  3. pre.next直接指向curr.next,实现批量删除
  4. 没有重复时,正常移动pre指针

4.3 处理重复节点的艺术

在实际编码中,处理重复节点有几个精妙之处:

  1. pre指针的滞后性:只有在确认无重复时才移动pre
  2. 批量删除:发现重复后一次性跳过所有重复节点
  3. dummy节点的使用:统一处理头节点可能被删除的情况

特殊测试用例:

  • 全重复链表:1->1->1->1
  • 头尾重复:1->1->2->3->3
  • 无重复链表:1->2->3
  • 空链表

5. 链表操作通用技巧总结

5.1 指针操作的四种基本模式

通过这三道题目,我总结了链表操作的四种基本模式:

  1. 遍历模式:curr = curr.next
  2. 翻转模式
    next_node = curr.next curr.next = prev prev = curr curr = next_node
  3. 快慢指针:用于检测环或找中点
  4. 多指针协同:如pre、curr、next_group配合

5.2 调试链表问题的实用技巧

  1. 可视化工具
    • 使用printList函数打印链表
    • 画出示意图辅助理解指针关系
  2. 边界检查清单
    • 空链表
    • 单节点链表
    • 头/尾节点特殊处理
  3. 防御性编程
    if not head or not head.next: return head

5.3 性能优化与代码简洁之道

  1. 虚拟头节点:统一处理逻辑,减少条件判断
  2. 提前返回:发现特殊情况立即返回,避免不必要操作
  3. 指针复用:合理利用已有指针,减少变量创建
  4. 循环不变式:明确循环中哪些关系保持不变

刷题半年后,我最大的体会是:链表问题看似复杂,实则规律性强。掌握这几种基本模式后,80%的题目都能迎刃而解。建议初学者从这三大操作入手,反复练习直到能闭眼写出无bug的代码。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询