故事「拯救公主的冒险」

67 阅读4分钟

用一个「拯救公主的冒险」故事,结合 5 道高频链表算法题,帮你彻底掌握链表解题套路!

一、故事背景:拯救被囚禁的公主

任务
你是骑士,要通过一系列关卡(链表算法题)拯救被囚禁的公主。每个关卡都有一个守卫,只有解开谜题才能通关!

二、高频算法题 1:反转链表(LeetCode 206)

关卡描述

守卫说:“想要通关,必须反转这条链表!”
链表:1→2→3→4→5 → 反转后:5→4→3→2→1

解题思路

  • 用三个指针:prev(前一个节点)、curr(当前节点)、next(下一个节点)。
  • 每次将 curr 指向 prev,然后三个指针同时后移。

Java 代码

java

public ListNode reverseList(ListNode head) {
    ListNode prev = null;
    ListNode curr = head;
    
    while (curr != null) {
        ListNode next = curr.next;  // 保存下一个节点
        curr.next = prev;           // 当前节点指向前一个
        prev = curr;                // 前一个指针后移
        curr = next;                // 当前指针后移
    }
    
    return prev;  // 新的头节点
}

三、高频算法题 2:链表中间节点(LeetCode 876)

关卡描述

守卫说:“找到链表的中间节点,我就放你过去!”
链表:1→2→3→4→5 → 中间节点:3

解题思路

  • 快慢指针:快指针每次走两步,慢指针每次走一步。
  • 当快指针到达末尾时,慢指针正好在中间。

Java 代码

java

public ListNode middleNode(ListNode head) {
    ListNode slow = head;
    ListNode fast = head;
    
    while (fast != null && fast.next != null) {
        slow = slow.next;      // 慢指针走一步
        fast = fast.next.next; // 快指针走两步
    }
    
    return slow;  // 中间节点
}

四、高频算法题 3:链表是否有环(LeetCode 141)

关卡描述

守卫说:“这条链表可能有环,证明给我看!”
链表:1→2→3→4→2(环从 2 开始) → 有环

解题思路

  • 快慢指针:如果链表有环,快指针最终会追上慢指针。

Java 代码

java

public boolean hasCycle(ListNode head) {
    ListNode slow = head;
    ListNode fast = head;
    
    while (fast != null && fast.next != null) {
        slow = slow.next;
        fast = fast.next.next;
        
        if (slow == fast) {  // 相遇,说明有环
            return true;
        }
    }
    
    return false;  // 无环
}

五、高频算法题 4:合并两个有序链表(LeetCode 21)

关卡描述

守卫说:“把这两条有序链表合并成一条,我就放行!”
链表 1:1→3→5
链表 2:2→4→6
合并后:1→2→3→4→5→6

解题思路

  • 虚拟头节点:创建一个虚拟头节点,比较两个链表的当前节点,选较小的接入。

Java 代码

java

public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
    ListNode dummy = new ListNode(0);  // 虚拟头节点
    ListNode tail = dummy;
    
    while (l1 != null && l2 != null) {
        if (l1.val < l2.val) {
            tail.next = l1;
            l1 = l1.next;
        } else {
            tail.next = l2;
            l2 = l2.next;
        }
        tail = tail.next;  // 尾指针后移
    }
    
    // 处理剩余节点
    if (l1 != null) tail.next = l1;
    if (l2 != null) tail.next = l2;
    
    return dummy.next;  // 虚拟头节点的下一个节点
}

六、高频算法题 5:删除倒数第 N 个节点(LeetCode 19)

关卡描述

守卫说:“删除链表的倒数第 2 个节点,否则别想过去!”
链表:1→2→3→4→5 → 删除后:1→2→3→5

解题思路

  • 双指针:快指针先走 N 步,然后快慢指针一起走,快指针到末尾时,慢指针正好在倒数第 N+1 个节点。

Java 代码

java

public ListNode removeNthFromEnd(ListNode head, int n) {
    ListNode dummy = new ListNode(0);
    dummy.next = head;
    ListNode fast = dummy;
    ListNode slow = dummy;
    
    // 快指针先走 N 步
    for (int i = 0; i <= n; i++) {
        fast = fast.next;
    }
    
    // 快慢指针一起走,直到快指针到末尾
    while (fast != null) {
        slow = slow.next;
        fast = fast.next;
    }
    
    // 删除倒数第 N 个节点
    slow.next = slow.next.next;
    
    return dummy.next;
}

七、链表解题通用技巧

  1. 虚拟头节点(Dummy Node)

    • 处理头节点可能变化的情况(如删除、合并)。
  2. 双指针(快慢指针)

    • 找中间节点、判断环、删除倒数第 N 个节点。
  3. 迭代与递归

    • 反转链表可用迭代或递归(递归更简洁,但可能栈溢出)。
  4. 画图辅助

    • 链表操作复杂时,画图能清晰展示指针变化。

八、关键总结

  • 反转链表:三指针迭代或递归。

  • 中间节点:快慢指针,快指针走两步,慢指针走一步。

  • 判断环:快慢指针,相遇则有环。

  • 合并有序链表:虚拟头节点,比较接入。

  • 删除倒数第 N 个节点:双指针,快指针先走 N 步。

记忆口诀

  • 链表解题靠指针,虚拟头、快慢走,画图理清关系网!

这样解释够简单了吗?如果还有疑问,随时告诉我! 😊