24. 两两交换链表中的节点
题目
要求
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
解答
迭代的思路就是考虑清楚下一个节点是什么,举个实际的例子来解释代码,1→2→3→4→null,首先我先确定了最后要返回的头节点,如果节点数大于 1,那返回的头节点肯定是 head.next.next,接下来进入循环,声明 pre 的目的是保留循环的前一个节点,这个后面有用,首先确定条件,head != null && head.next != null
,先保留第三个节点(3),因为在交换前两个节点会丢失第三个节点,然后交换前两个节点(1→2→1→2······),这个时候 pre(1) 的下一个节点交换后的第一个节点(1→2),接着交换后的第二个节点(这个时候 1 和 2 已经交换,所以第二个节点为 1)的下一个节点为前面保存的第三个节点(3),pre 为下一次循环节点(3)的前一个节点(1),head 为 3;
第二次开始:pre 为 1,head 为 3,进入循环,temp 为 null,交换节点得到 3→4→3→4·····,这个时候就是为什么要在外部声明 pre,交换之后头节点没了,pre.next = [head.next](http://head.next)
目的是 1→ 4,这样和前面连起来了,2→1→4→3,之后保留第三个节点,不然会出现死循环,基本就是这样了。
public static ListNode swapPairs(ListNode head) {
ListNode virtual = new ListNode(0);
if (head == null || head.next == null) {
return head;
} else {
// 确定返回的头节点
virtual.next = head.next;
}
// 保留第一个节点以及下一次循环的前一个节点
ListNode pre = head;
while (head != null && head.next != null) {
// 保留第三个节点
ListNode temp = head.next.next;
// 交换节点,这个地方会形成死循环
head.next.next = head;
// 第一个节点指向交换后的头节点
pre.next = head.next;
// 当前头节点等于第三个节点
head.next = temp;
// pre 指向下一次循环的前一个节点
pre = head;
// 下一次循环的头节点就是之前的第三个节点
head = temp;
}
return virtual.next;
}
接下来看看递归的思路,递归思路相对就简单了,在一次递归中,交换两个节点,并且让交换后的第二个节点的下一个节点等于下一次递归返回的节点,就 ok 了,代码如下:
public static ListNode swapPairs2(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode newHead = head.next;
head.next = swapPairs(head.next.next);
newHead.next = head;
return newHead;
}