链表两两交换是考察指针操作与递归思维的典型题目。掌握它,你对链表的指针操作和递归思维会有更深的理解。
核心思路与现实映射
生活中很多事情都像是'交换顺序'。比如排队时两人互换位置,或者整理书架时相邻书籍对调。在链表操作中,这对应着调整指针指向,让相邻节点的位置互换。
在实际业务中,这类逻辑常见于:
- 数据排序:局部重排用户列表显示顺序。
- 任务调度:调整队列中优先级相邻任务的执行顺序。
- 游戏设计:动态调整排行榜玩家位置。
方案一:递归实现
递归是最直观的思路。每次处理当前节点和下一个节点,交换它们的位置,然后递归处理剩余的链表。终止条件是当前节点为空或下一个节点为空。
时间复杂度 O(n),空间复杂度 O(n)(递归栈)。
public ListNode swapPairs(ListNode head) {
// 终止条件:空节点或只有一个节点
if (head == null || head.next == null) {
return head;
}
// 保存第二个节点
ListNode nextNode = head.next;
// 递归处理剩余部分
head.next = swapPairs(nextNode.next);
// 交换当前两个节点
nextNode.next = head;
return nextNode;
}
注意这里递归返回的是新的头节点,所以 nextNode 才是本次交换后的新起点。
方案二:迭代(带哑节点)
这是更符合工程实践的写法。引入一个哑节点(dummy node)作为辅助,方便统一处理头节点交换,避免单独判断。
时间复杂度 O(n),空间复杂度 O(1)。
public ListNode swapPairs(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode prev = dummy;
while (prev.next != null && prev.next.next != ) {
prev.next;
prev.next.next;
prev.next = second;
first.next = second.next;
second.next = first;
prev = first;
}
dummy.next;
}


