文章目录
一、问题介绍
题目链接:LeetCode - Swap Nodes in Pairs
题意简述:
给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
要求: 不能仅仅修改节点内部的值,而是需要实际交换节点。
例如:
输入:1 -> 2 -> 3 -> 4
输出:2 -> 1 -> 4 -> 3
二、示例与问题理解
假设链表为 1 -> 2 -> 3 -> 4:
我们需要把每一对相邻节点进行交换:
- 第 1、2 个节点交换:得到
2 -> 1 - 第 3、4 个节点交换:得到
4 -> 3 - 拼接后:
2 -> 1 -> 4 -> 3
三、解题思路分析
两种常见思路:
- 递归法: 利用函数调用栈两两交换节点。
- 迭代法: 使用指针在循环中手动调整指向。
核心逻辑
- 对于两个节点
first和second:- 交换它们的链接关系,使
second指向first - 再把前一段的尾部与新的头部连接
- 交换它们的链接关系,使
四、图表说明
1. 思维导图
Swap Nodes in Pairs
思路一:递归法
- 交换当前的两个节点 - 递归处理后续子链表 - 返回新的头结点 思路二:迭代法
- 通过循环交换每两个节点 - 使用临时指针控制前后连接
2. 交换流程图(以两个节点为例)
否
是
Start
是否存在两个节点可交换?
返回head
记录first和second节点
second.next = first
first.next = 递归处理后续节点
返回second作为新的头节点
五、解法一:递归法
原理说明
- 每次函数调用处理两个节点:
head与head.next - 交换后将第二个节点作为新的头结点,然后递归交换后续部分。
Java 代码示例
java
class Solution {
public ListNode swapPairs(ListNode head) {
// base case:链表为空或只有一个节点,直接返回
if (head == null || head.next == null) {
return head;
}
ListNode first = head;
ListNode second = head.next;
// 递归处理后续部分
first.next = swapPairs(second.next);
// 交换当前两个节点
second.next = first;
// 返回新的头结点
return second;
}
}
过程说明
例如 1 -> 2 -> 3 -> 4:
- 第一次递归交换
1和2,返回2 -> 1 - 再递归处理剩余的
3 -> 4,返回4 -> 3 - 最终合并为
2 -> 1 -> 4 -> 3
六、解法二:迭代法
原理说明
通过一个虚拟头结点 dummy 来简化前驱指针的处理,每次循环内交换两个相邻节点。
Java 代码示例
java
class Solution {
public ListNode swapPairs(ListNode head) {
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode prev = dummy;
while (head != null && head.next != null) {
ListNode first = head;
ListNode second = head.next;
// 交换
prev.next = second;
first.next = second.next;
second.next = first;
// 移动指针到下一组
prev = first;
head = first.next;
}
return dummy.next;
}
}
Mermaid 时序图说明
head second first prev head second first prev prev.next = second second.next = first first.next = nextPairHead
七、时间复杂度与空间复杂度分析
| 解法 | 时间复杂度 | 空间复杂度 | 说明 |
|---|---|---|---|
| 递归法 | O(n) | O(n) | 每次递归调用消耗栈空间 |
| 迭代法 | O(n) | O(1) | 仅使用常量级辅助指针 |
八、总结
- 递归法实现更简洁,思想优雅,但对栈空间要求较高。
- 迭代法较为实际,性能稳定且空间效率更好。
- 无论哪种方式,关键在于正确处理指针链接关系的变化。
推荐使用迭代法------更安全,不依赖系统调用栈。