24. 两两交换链表中的节点

913 阅读2分钟

题目描述

给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。

分析

输入:链表头节点 head 输出:变换后的链表的头节点

解题思路

题目要求我们两两翻转,实际上和其他的翻转没什么区别,需要考虑这么几件事:

头节点会被改变位置:到其他地方,所以用一个 dummyHead,最终返回结果的时候,直接 return dummyHead.next

翻转的方法:如果要翻转两个节点,那么首先应该保存后一个的 next,然后把它指向前一个指针,再让前一个指针的 next 指向保存的 next, 就完成了整个过程

翻转部分的前后引用:翻转部分的前后两个指针,我们称为 pre, succ。因为翻转之后的这部分链表实际上还是在整个的大链表里面的,所以我们要注意在翻转之后要把头尾给他拼起来。

我们可以这么做,从 pre.next 开始翻转,这部分在一个函数里执行,然后返回新的 head,让 pre.next 指向这个新的 head,就完成✅了和前边 pre 的拼接;那么对于 succ, 实际上我们注意到在翻转之后可以让指针在翻转的时候,继续向后移动,那么在最后,会有一个指针指向翻转部分的最后一个节点,另一个指针指向紧接着的 succ 节点。 我们把他们拼起来就可以了。

image.png

什么时候结束翻转:根据题意,因为要求是两个两个进行,所以剩余节点不够 2 的时候,就停止操作。那在代码里反应出来就是 .next.next.next 都要存在

代码

/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var swapPairs = function (head) {
  const dummyHead = new ListNode(null, head);
  let ret = dummyHead;

  let tmp = ret;
  while (tmp.next && tmp.next.next) {
    let pre = tmp.next,
      cur = tmp.next.next;

    pre.next = cur.next;
    cur.next = pre;
    tmp.next = cur;

    tmp = pre;
  }

  return ret.next;
};

复杂度

时间:O(N), 链表需要遍历一遍 空间:O(1), 存储几个指针(这题可以看出,递归需要更多内存,迭代就是常量级)