#24
中等
低频
哑节点迭代两两交换链表中的节点
这是一道围绕链表展开的高频练习。建议先掌握「哑节点迭代」这套写法,再结合下方步骤讲解理解状态维护、边界处理和复杂度取舍。
链表
题目分析
这道题表面上是在处理「两两交换链表中的节点」,但先要想清楚题目到底让你返回什么,以及过程中哪些约束必须一直满足。从题型上看,它主要在考 链表 这些能力。先别急着写代码,先把题目要求翻译成人话,明确结果是什么、约束是什么、过程里要持续维护什么。只有先把题目要求翻译成人话,后面的推荐代码才是在实现思路,而不是直接给答案。
接下来怎么看推荐代码: 带着这个理解再看推荐代码时,重点观察这条主线:用哑节点统一处理头结点交换,每次抓出相邻两个节点,重新连边后整体向前推进。
推荐代码
推荐解法:哑节点迭代
时间复杂度: O(n)
空间复杂度: O(1)
核心思路: 用哑节点统一处理头结点交换,每次抓出相邻两个节点,重新连边后整体向前推进。
class Solution {
public ListNode swapPairs(ListNode head) {
ListNode dummy = new ListNode(0, head);
ListNode prev = dummy;
while (prev.next != null && prev.next.next != null) {
ListNode first = prev.next;
ListNode second = first.next;
first.next = second.next;
second.next = first;
prev.next = second;
prev = first;
}
return dummy.next;
}
}结构化讲解
面试时怎么讲
开场思路
这题我会用哑节点配合迭代,逐对交换节点。
核心过程
- 先创建哑节点指向头结点。
- 每次取出
prev后面的两个节点。 - 调整三条指针,把第二个节点换到前面。
- 然后让
prev移到这一对交换后的尾部,继续处理下一对。
复杂度总结
时间复杂度 O(n),空间复杂度 O(1)。
面试补一句:这题答得稳不稳,取决于你能不能把三条指针的重连顺序说清楚。
核心思路
链表两两交换的难点不是交换值,而是正确维护指针关系。引入哑节点后,每一轮只需要固定处理三个连接关系,逻辑会稳定很多。
步骤讲解
1
先放一个哑节点
让头结点参与交换时也能和普通位置统一处理。
为什么这样做:否则第一对节点交换后需要单独改头指针。
对应代码提示:ListNode dummy = new ListNode(0, head);
2
抓出一对节点并重连
设 first、second 为当前一对节点,按顺序重接它们与后继。
为什么这样做:交换的是节点位置,不是节点值。
对应代码提示:first.next = second.next; second.next = first; prev.next = second;
3
移动到下一轮起点
交换后 first 变成这对节点的尾部,prev 应该移动到它。
为什么这样做:下一轮要从新尾部后面继续处理。
对应代码提示:prev = first;
易错点
先改 `second.next` 导致链表断开
如果没先保存后继,后面的节点可能丢失。
正确理解:按固定顺序操作:先记录,再改尾,再改头。
交换节点值而不是节点本身
虽然这题有时也能过,但不符合链表指针题的考察重点。
正确理解:面试里优先展示真正的指针重连。
复杂度与适用判断
时间复杂度:O(n)
空间复杂度:O(1)
比其他方案更好在哪里:比递归更容易控制指针细节,也没有递归栈开销。
适用判断:链表里涉及头节点也要参与重连时,哑节点几乎总是加分写法。
额外提醒
- 哑节点让“交换第一对”和“交换中间任意一对”变成同一个模板。