给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
示例 1:
输入:head = [1,2,3,4] 输出:[2,1,4,3]
示例 2:
输入:head = [] 输出:[]
示例 3:
输入:head = [1] 输出:[1]
提示:
- 链表中节点的数目在范围
[0, 100]
内 0 <= Node.val <= 100
要解决这个问题,我们可以使用一个迭代的方法来遍历链表,并两两交换相邻的节点。下面是实现的步骤和代码:
### 步骤
1. **创建一个虚拟头节点**: 这样可以简化对头节点的处理。
2. **使用一个指针**: 从虚拟头节点开始,遍历链表。
3. **交换节点**: 每次取出当前节点及其下一个节点,进行交换,然后更新指针。
4. **重复直到链表末尾**: 一直进行上述操作,直到没有更多节点可以交换。
### Java 实现
class ListNode {
int val;
ListNode next;
ListNode(int x) { val = x; }
}
public class Solution {
public ListNode swapPairs(ListNode head) {
// 创建一个虚拟头节点
ListNode dummy = new ListNode(0);
dummy.next = head;
// 初始化当前指针
ListNode current = dummy;
// 当有至少两个节点可以交换时
while (current.next != null && current.next.next != null) {
// 指向要交换的两个节点
ListNode firstNode = current.next;
ListNode secondNode = current.next.next;
// 进行交换
firstNode.next = secondNode.next; // 让第一个节点指向第三个节点
secondNode.next = firstNode; // 让第二个节点指向第一个节点
current.next = secondNode; // 将当前节点的下一个指向第二个节点
// 移动当前指针
current = firstNode; // 当前指针移到第一个节点
}
// 返回新的头节点
return dummy.next;
}
}
### 代码解释
- **ListNode 类**: 定义链表节点,包含值和指向下一个节点的指针。
- **swapPairs 方法**:
- 使用一个虚拟头节点 `dummy`,这样在处理头节点交换时更为方便。
- 使用一个 `current` 指针来遍历链表。
- 在 `while` 循环中检查 `current.next` 和 `current.next.next` 是否存在,确保可以进行交换。
- 通过改变指针的 `next` 属性来交换节点。
- **返回**: 最后返回 `dummy.next`,即新的头节点。
这个实现的时间复杂度为 O(n),空间复杂度为 O(1),因为我们只使用了常量级的额外空间。
除此之外还有别的解决方法例如递归和不递归
递归解法的原理主要是利用递归的特性来交换链表中每对相邻的节点。我们逐步解析这个递归解法的细节和原理。
### 递归解法的步骤
1. **基例(Base Case)**:
- 首先,通过条件 `if (head == null || head.next == null)` 来检查链表是否为空或只有一个节点。如果是这种情况,就无需进行任何交换,直接返回当前节点 `head`。
2. **保存下一节点**:
- `ListNode next = head.next;` 保存当前节点的下一个节点,用于后续交换。
3. **递归调用**:
- `head.next = swapPairs(next.next);` 这一步是递归的核心:我们通过递归调用 `swapPairs(next.next)` 来处理下一个节点的交换。换句话说,在这个递归调用中,我们试图解决当前节点的下一个节点对的交换。
4. **完成当前节点对的交换**:
- `next.next = head;` 这一步将 `next` 节点指向当前的 `head` 节点,因此这两个节点完成了交换。
5. **返回新的头节点**:
- `return next;` 最后,返回 `next`,它成为交换后的当前对的头节点(即在交换后,原先的第二个节点现在成为了这一对的前端节点)。
假设我们有链表 `[1 -> 2 -> 3 -> 4]`,我们可以看到递归是如何逐步解决这个问题的:
- 第一层递归:`swapPairs(1 -> 2 -> 3 -> 4)`
- `next = 2`
- 等待 `head.next` 的结果,递归到下一层
- 第二层递归:`swapPairs(3 -> 4)`
- `next = 4`
- 等待 `head.next` 的结果,递归到下一层
- 第三层递归:`swapPairs(null)`
- 返回 `null`(基例)
- 回到第二层:
- 处理 `4 -> 3` 进行交换,最终返回 `4 -> 3 -> null`
- 再回到第一层:
- 将 `2 -> (4 -> 3)` 连接,返回 `2 -> 1 -> (4 -> 3)`
最终得到链表的新顺序为 `[2 -> 1 -> 4 -> 3]`。
class Solution {
public ListNode swapPairs(ListNode head) {
if(head == null || head.next == null){
return head;
}
ListNode next = head.next;
head.next = swapPairs(next.next);
next.next = head;
return next;
}
}
不递归:
class ListNode {
int val;
ListNode next;
ListNode(int x) { val = x; }
}
class Solution {
public ListNode swapPairs(ListNode head) {
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode temp = dummy;
while (temp.next != null && temp.next.next != null) {
// 调用 swap 方法进行节点交换
temp = swap(temp);
}
return dummy.next;
}
private ListNode swap(ListNode temp) {
// 指向要交换的两个节点
ListNode start = temp.next;
ListNode end = temp.next.next;
// 执行交换
temp.next = end; // 当前节点指向第二个节点
start.next = end.next; // 第一个节点指向第三个节点
end.next = start; // 第二个节点指向第一个节点
// 返回新的 temp 位置,指向新的第一个节点
return start; // 更新 temp 为之前的第一个节点
}
}