链表中等2 种解法
#24两两交换链表中的节点
不修改节点值,将单链表中每两个相邻节点交换。
#链表#递归#迭代
原题
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
示例 1:
输入:head = [1,2,3,4] 输出:[2,1,4,3]
示例 2:
输入:head = [] 输出:[]
示例 3:
输入:head = [1] 输出:[1]
提示:
- 链表中节点的数目在范围
[0, 100]内 0 <= Node.val <= 100
解题主线
- 哨兵节点让首对节点的交换与后续节点对使用同一套重连逻辑。
- 递归中第二个节点成为当前段新头,第一个节点连接已交换完成的后缀。
解法 1:迭代重连
让 previous 指向每一对节点的前驱,交换后移动到该对的新尾部。
-
时间复杂度: O(n)
-
空间复杂度: O(1)
final class ListNode {
int val;
ListNode next;
ListNode(int val) {
this.val = val;
}
ListNode(int val, ListNode next) {
this.val = val;
this.next = next;
}
}
final class Solution {
public ListNode swapPairs(ListNode head) {
// 哨兵统一首对节点与后续节点对的前驱重连逻辑
ListNode dummy = new ListNode(0, head);
ListNode previous = dummy;
// 仅在后方至少还有两个节点时执行交换
while (previous.next != null && previous.next.next != null) {
ListNode first = previous.next;
ListNode second = first.next;
// 先接回后缀,再反转当前二元组,避免链表断裂
first.next = second.next;
second.next = first;
previous.next = second;
// first 已成为当前二元组尾部,也是下一轮的前驱
previous = first;
}
return dummy.next;
}
}解法 2:递归交换
先递归交换第二个节点之后的链表,再翻转当前两个节点的连接。
-
时间复杂度: O(n)
-
空间复杂度: O(n),递归栈
final class ListNode {
int val;
ListNode next;
ListNode(int val) {
this.val = val;
}
ListNode(int val, ListNode next) {
this.val = val;
this.next = next;
}
}
final class Solution {
public ListNode swapPairs(ListNode head) {
// 不足两个节点时无法成对交换,直接保留当前后缀
if (head == null || head.next == null) return head;
ListNode second = head.next;
// 原首节点连接已经完成两两交换的剩余链表
head.next = swapPairs(second.next);
// 第二个节点成为当前二元组的新头
second.next = head;
return second;
}
}边界与易错点
- 重连前先保存两个节点引用,避免修改 next 后丢失后缀。
- 奇数长度链表的最后一个节点保持原位。
整理来源
由旧仓库源码复核、去重并整理;展示代码已按 Java 21 语义修正明显问题。
medium/Q024_swapPairs.java