题目

题目来源:力扣(LeetCode)

给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。

你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

示例 1:
image.png

输入:head = [1,2,3,4]
输出:[2,1,4,3]
示例 2:

输入:head = []
输出:[]
示例 3:

输入:head = [1]
输出:[1]

思路分析

递归解法

这道题可以通过递归的方式实现两两交换链表中的节点。

首先我们来看下它的终止条件。如果链表中没有接节点,或者链表中只有一个节点,此时是无法进行交换的,则终止递归。

如果链表中至少有两个节点,那么在两两交换链表中的节点之后,原始链表的头节点变成新链表的第二个节点,原始链表的第二个节点变成新的链表的头节点。

链表中的其余节点的两两交换可以递归地实现。在对链表中的其余节点递归地两两交换之后,更新节点之间的指针关系,即可完成整个链表的两两交换。

我们用 head 表示原始链表的头节点,同时也是新链表的第二个节点,用 newHead 表示新链表的头节点,也就是原始链表的第二个节点,因为是两两交换,那么原始链表中的其余节点的头节点是 newHead.next 。令 head.next = swapPairs(newHead.next),表示将其余节点进行两两交换,交换后的新的头节点为 head 的下一个节点,然后令 newHead.next = head ,即完成了所有节点的交换,最后返回新的链表的头节点 newHead 。

  1. var swapPairs = function(head) {
  2. if (!head || !head.next) {
  3. return head;
  4. }
  5. // 新链表的头节点为 原始链表的第二个节点
  6. const newHead = head.next;
  7. // swapPairs 将给定的链表中的相邻节点两两交换后返回,返回的是交换完成的链表的头节点
  8. // 交换后的新的头节点为 head 的下一个节点(即新链表的第3个、第5个、第 2n+1 个节点) (其中 n 为 1)
  9. head.next = swapPairs(newHead.next);
  10. // 将原始链表的头节点变为新链表的第二个节点
  11. newHead.next = head;
  12. return newHead;
  13. }

迭代解法

1、首先创建一个虚拟头节点 hair,让 hair 的 next 指针域指向链表的头节点:hair.next = head
2、然后定义一个 curr 变量,表示当前到达的节点,初始时令 curr 指向虚拟头节点 hair,每次需要交换的就是 curr 后面的两个节点。
3、对于 curr 后面的两个节点,我们分别用 变量node1 和 变量node2 表示:
4、node1 和 node2 进行交换后,node2 变成了新的头节点,node1 变成了第二个节点,因此,我们将 curr 所指向的节点的后继指针指向 node2所指向的节点 curr.next = node2 ,然后将 node1 的后继指针指向 node2 所指向节点的下一个节点 node1 = node2.next
5、接下来将 node2 所指向的节点的后继指针指向 node1 所指向的节点
此时变量node1 所指向的节点和 node2所指向的节点完成了交换,我们整理一下链表,如下:
6、接下来,将 curr 变量指向变量 node1 指向的变量,下一组待交换的节点 3 和 4,还是一样,分别使用 node1 和 node2 表示,其中 node1 = curr.next ,node2 = node.next
6、我们同样将 curr 所指向的节点的后继指针指向 node2所指向的节点 curr.next = node2 ,将 node1 所指向的节点的后继指针指向 node2 所指向节点的下一个节点 node1 = node2.next,然后将 node2 所指向的节点的后继指针指向 node1 所指向的节点,此时完成了节点3 和节点4 的交换:
我们整理一下链表,如下:
7、对链表中的其余节点进行两两交换,直到全部节点都被两两交换。两两交换链表中的节点之后,新的链表的头节点是 hair.next,返回新的链表的头节点即可。

  1. var swapPairs = function(head) {
  2. //创建一个虚拟头节点 hair
  3. const hair = new ListNode(0);
  4. // 将虚拟头节点的后继指针指向 链表的头节点
  5. hair.next = head;
  6. // 定义 curr 变量,表示当前到达的节点,初始时令 curr 指向 hair
  7. let curr = hair;
  8. while (curr.next !== null && curr.next.next !== null) {
  9. // 分别用变量node1 和 变量node2 表示需要交换的两个节点
  10. const node1 = curr.next;
  11. const node2 = curr.next.next;
  12. // 将 curr 变量所指向的节点的后继指针指向 node2 所指向的节点
  13. curr.next = node2;
  14. // 将 node1 所指向的节点的后继指针指向 node2 所指向节点的后一个节点
  15. node1.next = node2.next;
  16. // 将 node2 所指向的节点的后继指针指向 node1 所指向的节点,完成两个节点的交换
  17. node2.next = node1;
  18. // 完成了两个节点的交换后,令 curr 指向 node1 所指向的节点,重复上述步骤,完成其余两两节点的交换
  19. curr = node1;
  20. }
  21. // 两两交换链表中的节点之后,新的链表的头节点是 hair.next,返回新的链表的头节点
  22. return hair.next;
  23. };