LeetCode 24. 两两交换链表中的节点
📌 题目描述
题目级别:中等
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
- 示例 1:
输入:head = [1,2,3,4]
输出:[2,1,4,3]
💡 破题思路:Dummy 节点与指针重定向
在链表中进行"交换"或"删除"操作时,最棘手的问题往往是如何处理头节点 的变化。
为了让头节点的变化逻辑和普通节点完全一致,我们引入了链表题的万能钥匙:虚拟头节点 (Dummy Node)。
核心逻辑拆解:
每次我们要交换两个相邻节点(设为 n1 和 n2)时,我们必须要知道它们前一个节点 的位置(设为 cur),因为交换完成后,前一个节点的 next 指针需要重新指向新的头节点(即 n2)。
具体的"指针舞步"如下:
- 锁定位置:找到
cur(初始为dummy),并确认它后面至少还有两个节点可以交换。 - 标记目标:定义
n1 = cur->next,n2 = cur->next->next。 - 断开与重连(核心 3 步) :
n1->next = n2->next;(让原来的第一个节点连上后续的长尾巴,防止断链)n2->next = n1;(让第二个节点回头指向第一个节点,完成内部翻转)cur->next = n2;(让守门员cur连上翻转后的新头部n2)
- 推进战线:交换完成后,
n1已经跑到了后面,它现在是下一对节点的前驱节点。我们让cur = n1,继续下一轮循环。
💻 C++ 代码实现 (原汁原味作者版)
cpp
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
// 引入虚拟头节点,巧妙化解真实头节点被交换的边界问题
ListNode *dummy = new ListNode(0, head);
ListNode *cur = dummy;
// 只要 cur 后面还有至少两个节点,就可以继续交换
while (cur->next && cur->next->next)
{
// 标记待交换的两个节点
ListNode *n1 = cur->next;
ListNode *n2 = cur->next->next;
// 开始"指针舞步"
n1->next = n2->next; // 步骤 1:n1 牵手 n2 后面的节点
n2->next = n1; // 步骤 2:n2 回头拥抱 n1
cur->next = n2; // 步骤 3:前面的链表接上新的局部头节点 n2
// cur 移动到已经交换完毕的末尾节点 (即 n1),准备下一轮
cur = n1;
}
// 返回虚拟头节点的下一个节点,即真正的链表头
return dummy->next;
}
};