题目描述
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
分析
输入:链表头节点 head
输出:变换后的链表的头节点
解题思路
题目要求我们两两翻转,实际上和其他的翻转没什么区别,需要考虑这么几件事:
头节点会被改变位置:到其他地方,所以用一个 dummyHead,最终返回结果的时候,直接 return dummyHead.next
翻转的方法:如果要翻转两个节点,那么首先应该保存后一个的 next,然后把它指向前一个指针,再让前一个指针的 next 指向保存的 next, 就完成了整个过程
翻转部分的前后引用:翻转部分的前后两个指针,我们称为 pre, succ。因为翻转之后的这部分链表实际上还是在整个的大链表里面的,所以我们要注意在翻转之后要把头尾给他拼起来。
我们可以这么做,从 pre.next 开始翻转,这部分在一个函数里执行,然后返回新的 head,让 pre.next 指向这个新的 head,就完成✅了和前边 pre 的拼接;那么对于 succ,
实际上我们注意到在翻转之后可以让指针在翻转的时候,继续向后移动,那么在最后,会有一个指针指向翻转部分的最后一个节点,另一个指针指向紧接着的 succ 节点。
我们把他们拼起来就可以了。
什么时候结束翻转:根据题意,因为要求是两个两个进行,所以剩余节点不够 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), 存储几个指针(这题可以看出,递归需要更多内存,迭代就是常量级)