链表问题的通用解题经验和技巧模板

一、链表基础知识

1.1 链表结构

class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val    # 节点值
        self.next = next  # 指向下一个节点的指针

1.2 链表 vs 数组

特性链表数组
访问O(n) 顺序访问O(1) 随机访问
插入/删除O(1) 修改指针O(n) 移动元素
内存分散,有指针开销连续
索引❌ 不支持✅ 支持

二、核心技巧总结

技巧1: 虚拟头节点(Dummy Node)⭐⭐⭐

何时使用:

  • 可能修改头节点的问题
  • 需要返回新链表的问题
  • 合并、删除节点的问题

模板:

def solution(head):
    dummy = ListNode(0)  # 创建虚拟头
    dummy.next = head
    curr = dummy
    
    # ... 处理逻辑
    
    return dummy.next  # 返回真正的头节点

示例:删除链表中的节点

# 不用虚拟头节点(复杂)
def deleteNode(head, val):
    # 特殊处理头节点
    if head.val == val:
        return head.next
    
    curr = head
    while curr.next:
        if curr.next.val == val:
            curr.next = curr.next.next
            break
        curr = curr.next
    return head

# 用虚拟头节点(简洁)
def deleteNode(head, val):
    dummy = ListNode(0)
    dummy.next = head
    curr = dummy
    
    while curr.next:
        if curr.next.val == val:
            curr.next = curr.next.next
            break
        curr = curr.next
    
    return dummy.next  # 统一处理

技巧2: 快慢指针(Two Pointers)⭐⭐⭐

常见应用:

应用1: 找中点
def findMiddle(head):
    """找链表中点"""
    slow = fast = head
    while fast and fast.next:
        slow = slow.next
        fast = fast.next.next
    return slow  # slow 指向中点
应用2: 判断环
def hasCycle(head):
    """判断是否有环"""
    slow = fast = head
    while fast and fast.next:
        slow = slow.next
        fast = fast.next.next
        if slow == fast:
            return True
    return False
应用3: 找倒数第k个节点
def findKthFromEnd(head, k):
    """找倒数第k个节点"""
    fast = slow = head
    
    # fast 先走 k 步
    for _ in range(k):
        if not fast:
            return None
        fast = fast.next
    
    # 一起走,fast 到末尾时,slow 在倒数第k个
    while fast:
        slow = slow.next
        fast = fast.next
    
    return slow
应用4: 删除倒数第k个节点
def removeKthFromEnd(head, k):
    """删除倒数第k个节点"""
    dummy = ListNode(0)
    dummy.next = head
    fast = slow = dummy
    
    # fast 先走 k+1 步
    for _ in range(k + 1):
        fast = fast.next
    
    # 一起走
    while fast:
        slow = slow.next
        fast = fast.next
    
    # slow.next 就是要删除的节点
    slow.next = slow.next.next
    
    return dummy.next

快慢指针速查表:

问题slow 速度fast 速度初始位置结果
找中点1步2步都在headslow到中点
判断环1步2步都在head相遇=有环
找倒数第k个1步1步fast先走k步slow是目标

技巧3: 反转链表模板 ⭐⭐⭐

迭代版本:

def reverseList(head):
    """三指针反转"""
    prev = None
    curr = head
    
    while curr:
        next_node = curr.next  # 1. 保存下一个
        curr.next = prev       # 2. 反转指针
        prev = curr            # 3. 移动prev
        curr = next_node       # 4. 移动curr
    
    return prev

递归版本:

def reverseList(head):
    """递归反转"""
    if not head or not head.next:
        return head
    
    new_head = reverseList(head.next)
    head.next.next = head
    head.next = None
    
    return new_head

反转部分链表:

def reverseBetween(head, left, right):
    """反转 [left, right] 区间"""
    dummy = ListNode(0)
    dummy.next = head
    prev = dummy
    
    # 1. 找到 left-1 位置
    for _ in range(left - 1):
        prev = prev.next
    
    # 2. 反转 [left, right]
    curr = prev.next
    for _ in range(right - left):
        next_node = curr.next
        curr.next = next_node.next
        next_node.next = prev.next
        prev.next = next_node
    
    return dummy.next

技巧4: 递归思维 ⭐⭐

递归三要素:

def recursion(head):
    # 1. 终止条件(Base Case)
    if not head or not head.next:
        return head
    
    # 2. 递归调用(假设子问题已解决)
    result = recursion(head.next)
    
    # 3. 当前层处理
    # 处理当前节点和子问题结果的关系
    
    return result

递归模板应用:

# 删除链表中的节点
def deleteNode(head, val):
    if not head:
        return None
    if head.val == val:
        return head.next
    head.next = deleteNode(head.next, val)
    return head

# 合并两个有序链表
def mergeTwoLists(l1, l2):
    if not l1:
        return l2
    if not l2:
        return l1
    if l1.val <= l2.val:
        l1.next = mergeTwoLists(l1.next, l2)
        return l1
    else:
        l2.next = mergeTwoLists(l1, l2.next)
        return l2

技巧5: 哈希表辅助 ⭐⭐

适用场景:

  • 检测环/重复
  • 查找节点
  • 记录访问状态
# 判断有环
def hasCycle(head):
    visited = set()
    curr = head
    while curr:
        if curr in visited:
            return True
        visited.add(curr)
        curr = curr.next
    return False

# 找环的入口
def detectCycle(head):
    visited = set()
    curr = head
    while curr:
        if curr in visited:
            return curr
        visited.add(curr)
        curr = curr.next
    return None

技巧6: 双链表拼接 ⭐

处理相交链表:

def getIntersection(headA, headB):
    """双指针消除长度差"""
    pA, pB = headA, headB
    
    while pA != pB:
        pA = pA.next if pA else headB
        pB = pB.next if pB else headA
    
    return pA

三、常见问题类型及模板

类型1: 链表遍历

# 模板
def traverse(head):
    curr = head
    while curr:
        # 处理 curr
        print(curr.val)
        curr = curr.next

类型2: 链表反转

# 完全反转
def reverse(head):
    prev = None
    curr = head
    while curr:
        next_node = curr.next
        curr.next = prev
        prev = curr
        curr = next_node
    return prev

# 部分反转
def reverseBetween(head, left, right):
    # 使用虚拟头节点 + 头插法
    pass

类型3: 链表合并

# 合并两个有序链表
def merge(l1, l2):
    dummy = ListNode(0)
    curr = dummy
    
    while l1 and l2:
        if l1.val <= l2.val:
            curr.next = l1
            l1 = l1.next
        else:
            curr.next = l2
            l2 = l2.next
        curr = curr.next
    
    curr.next = l1 if l1 else l2
    return dummy.next

类型4: 链表删除

# 删除值为val的所有节点
def deleteValue(head, val):
    dummy = ListNode(0)
    dummy.next = head
    curr = dummy
    
    while curr.next:
        if curr.next.val == val:
            curr.next = curr.next.next
        else:
            curr = curr.next
    
    return dummy.next

# 删除重复节点(保留一个)
def deleteDuplicates(head):
    curr = head
    while curr and curr.next:
        if curr.val == curr.next.val:
            curr.next = curr.next.next
        else:
            curr = curr.next
    return head

类型5: 链表排序

# 归并排序
def sortList(head):
    if not head or not head.next:
        return head
    
    # 找中点
    slow, fast = head, head.next
    while fast and fast.next:
        slow = slow.next
        fast = fast.next.next
    
    # 分割
    mid = slow.next
    slow.next = None
    
    # 递归排序
    left = sortList(head)
    right = sortList(mid)
    
    # 合并
    return merge(left, right)

四、调试技巧

4.1 打印链表

def print_list(head, name="链表"):
    values = []
    curr = head
    count = 0
    while curr and count < 20:  # 防止死循环
        values.append(str(curr.val))
        curr = curr.next
        count += 1
    print(f"{name}: {' → '.join(values)}")

4.2 可视化节点

def visualize(head):
    curr = head
    nodes = []
    visited = set()
    
    while curr:
        if curr in visited:
            nodes.append(f"({curr.val}*)←环")
            break
        visited.add(curr)
        nodes.append(str(curr.val))
        curr = curr.next
    
    print(" → ".join(nodes))

4.3 检查环

def check_cycle(head):
    """调试时检查是否意外形成环"""
    slow = fast = head
    while fast and fast.next:
        slow = slow.next
        fast = fast.next.next
        if slow == fast:
            print("⚠️ 警告:检测到环!")
            return True
    return False

五、常见错误及避免方法

错误1: 空指针访问

# ❌ 错误
curr = curr.next
print(curr.val)  # curr 可能是 None

# ✅ 正确
if curr:
    curr = curr.next
    if curr:
        print(curr.val)

# 或者
while curr and curr.next:
    curr = curr.next

错误2: 丢失节点

# ❌ 错误
curr.next = curr.next.next  # 没保存 curr.next
# curr.next 节点丢失了!

# ✅ 正确
next_node = curr.next  # 先保存
curr.next = next_node.next

错误3: 死循环

# ❌ 错误:形成环
node1.next = node2
node2.next = node1  # 死循环!

# ✅ 正确:断开环
node1.next = node2
node2.next = None

错误4: 修改了不该修改的

# ❌ 错误:修改了输入链表
def process(head):
    head = head.next  # 只是局部变量改变
    return head

# ✅ 正确:如果要修改,明确说明
def process(head):
    new_head = head.next
    head.next = None  # 明确断开
    return new_head

六、题型识别速查表

关键词可能的解法典型题目
找中点快慢指针链表中点、回文链表
快慢指针/哈希表环形链表、环的入口
倒数第k个快慢指针删除倒数第k个
反转迭代/递归反转链表、K组反转
合并双指针合并有序链表
删除虚拟头节点删除节点、去重
相加模拟两数相加
相交双指针拼接相交链表
排序归并排序链表排序
随机蓄水池抽样随机节点

七、做题流程

1. 理解题意
   ├─ 输入是什么?
   ├─ 输出是什么?
   ├─ 有哪些限制?
   └─ 边界情况?

2. 选择技巧
   ├─ 需要修改头节点?→ 虚拟头节点
   ├─ 找中点/环?→ 快慢指针
   ├─ 反转?→ 三指针迭代/递归
   └─ 合并/删除?→ 虚拟头节点 + 双指针

3. 画图模拟
   ├─ 画出初始状态
   ├─ 画出每一步变化
   └─ 确认最终状态

4. 写代码
   ├─ 先写主逻辑
   ├─ 再处理边界
   └─ 添加注释

5. 测试
   ├─ 空链表
   ├─ 单节点
   ├─ 两个节点
   └─ 正常情况

八、刷题顺序建议

入门级(必做)

  1. 反转链表
  2. 合并两个有序链表
  3. 删除链表节点
  4. 链表中点
  5. 环形链表

进阶级

  1. 环形链表II(找入口)
  2. 相交链表
  3. 回文链表
  4. 删除倒数第k个节点
  5. 两数相加

高级

  1. 反转链表II(部分反转)
  2. K个一组反转
  3. 排序链表
  4. 合并K个有序链表
  5. 复制带随机指针的链表

九、记忆口诀

链表题目不要慌,几个技巧记心上:

虚拟头节点,简化边界情况;
快慢双指针,中点和环都能找;
反转三步走,保存反转再移动;
递归要清晰,终止递归加处理;
画图很重要,指针变化要看清;
边界要考虑,空链单节要测试。

十、模板代码库

# 1. 虚拟头节点模板
def template_dummy(head):
    dummy = ListNode(0)
    dummy.next = head
    curr = dummy
    # ... 处理
    return dummy.next

# 2. 快慢指针模板
def template_two_pointers(head):
    slow = fast = head
    while fast and fast.next:
        slow = slow.next
        fast = fast.next.next
    return slow

# 3. 反转链表模板
def template_reverse(head):
    prev = None
    curr = head
    while curr:
        next_node = curr.next
        curr.next = prev
        prev = curr
        curr = next_node
    return prev

# 4. 递归模板
def template_recursion(head):
    if not head or not head.next:
        return head
    result = template_recursion(head.next)
    # 处理当前节点
    return result

# 5. 合并模板
def template_merge(l1, l2):
    dummy = ListNode(0)
    curr = dummy
    while l1 and l2:
        if l1.val <= l2.val:
            curr.next = l1
            l1 = l1.next
        else:
            curr.next = l2
            l2 = l2.next
        curr = curr.next
    curr.next = l1 if l1 else l2
    return dummy.next

掌握这些技巧和模板,链表问题就能游刃有余!关键是多画图、多模拟、多练习

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值