用一个「拯救公主的冒险」故事,结合 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;
}
七、链表解题通用技巧
-
虚拟头节点(Dummy Node) :
- 处理头节点可能变化的情况(如删除、合并)。
-
双指针(快慢指针) :
- 找中间节点、判断环、删除倒数第 N 个节点。
-
迭代与递归:
- 反转链表可用迭代或递归(递归更简洁,但可能栈溢出)。
-
画图辅助:
- 链表操作复杂时,画图能清晰展示指针变化。
八、关键总结
-
反转链表:三指针迭代或递归。
-
中间节点:快慢指针,快指针走两步,慢指针走一步。
-
判断环:快慢指针,相遇则有环。
-
合并有序链表:虚拟头节点,比较接入。
-
删除倒数第 N 个节点:双指针,快指针先走 N 步。
记忆口诀:
-
链表解题靠指针,虚拟头、快慢走,画图理清关系网!
这样解释够简单了吗?如果还有疑问,随时告诉我! 😊