链表——两两交换链表中的节点
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)
题目要求
- 两两交换相邻节点:1->2->3->4 → 2->1->4->3
- 不能改节点里的值,只能改指针指向
- 必须返回新头结点
核心思路:
-
虚拟头节点dummy(否则交换第一个节点时必崩)
-
每次处理3个指针:
- prev:要交换的两个节点的前一个
- first:第一个节点
- second:第二个节点
-
三步交换指针(顺序绝对不能错)
-
prev后移,继续下一组
完整代码实现如下:
struct ListNode {
int val;
ListNode *next;
ListNode() : val(0), next(nullptr) {}
ListNode(int x) : val(x), next(nullptr) {}
ListNode(int x, ListNode *next) : val(x, next) {}
};
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
// 虚拟头节点:解决交换头节点的问题
ListNode* dummy = new ListNode(0);
dummy->next = head;
ListNode* prev = dummy;
// 必须有两个节点才能交换
while (prev->next != nullptr && prev->next->next != nullptr) {
ListNode* first = prev->next;
ListNode* second = first->next;
// ====================== 核心三步交换 ======================
first->next = second->next; // 1 指向 3
second->next = first; // 2 指向 1
prev->next = second; // 前驱指向 2(新头)
// ==========================================================
// 前驱前移,准备下一组交换
prev = first;
}
return dummy->next;
}
};
最关键:为什么这三步顺序不能乱?
以prev->q->2->3举例:
1.first->next = second->next
意义:1指向3
目的:先把后面链保住,不然会断链
2.second->next = first
意义:2 指向 1
完成反转
3.prev->next = second
意义:前面的链接到 2
让 2 变成这一组的头
三步顺序错一个,直接链表断裂 / 死循环!
为什么必须用 dummy?
因为:
两两交换一定会改变整个链表的头结点!
原头是 1,交换后变成 2。
没有 dummy,你无法保存新头,也无法交换第一组节点。
有了dummy 永远站在最前面,不管第一组怎么交换,dummy->next 永远是最新的头!
dummy 就是为了:
让第一组节点也有前驱,和后面所有组逻辑完全统一,不用特判。
循环条件为什么是这样?
while (prev->next && prev->next->next)
意思:必须还有至少两个节点,才需要交换。
只剩一个节点或空,停止。
复杂度
- 时间:O(n) 一遍遍历
- 空间:**O(1) **仅用指针
浙公网安备 33010602011771号