给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
解法1 暴力解法
思路
两两交换节点,既然通过链表不好修改,那是不是可以将节点缓存到数组当中。
然后修改它们的顺序,最后再逐一修改 next
指针就好。
代码
js
function swapPairs(head: ListNode | null): ListNode | null {
if (!head) {
return null;
}
if (!head.next) {
return head;
}
let cur = head;
const nodeList = [];
while (cur) {
nodeList.push(cur);
cur = cur.next;
}
// 交换数组中链表的顺序
for (let i = 0; i < nodeList.length && nodeList[i] && nodeList[i + 1]; i = i + 2) {
const temp = nodeList[i + 1];
nodeList[i + 1] = nodeList[i];
nodeList[i] = temp;
}
// 修改每个节点的 next 指针
for (let i = 0; i < nodeList.length; i++) {
nodeList[i].next = i === nodeList.length - 1 ? null : nodeList[i + 1];
}
return nodeList[0];
};
时空复杂度
时间复杂度:三次遍历 O(n)
空间复杂度:使用额外数组存储 O(n)
解法2 虚拟头节点+双指针
思路
每当需要交换节点或者删除节点等操作,需要获取当前节点的上一个节点,以便操作 next
指针的时候,就可以考虑引入虚拟头节点。
这一题也是一样,两两交换节点时,需要获取上一个节点来操作指针。于是新建一个 dummyHead
连接到 head
。
再用 prev
变量指向上一个节点,循环遍历链表,两两交换,所以结束条件是当前节点和下一节点存在。
此时有三个节点 prev => first => second
。
而最终需要交换成 prev => second => first
。
交换完之后,指针向前走,此时 prev
需要指向 first
,它才是下一个两两交换节点的前一个节点。
代码
js
function swapPairs(head: ListNode | null): ListNode | null {
const dummyHead = new ListNode(-1, head);
let prev = dummyHead;
while (head && head.next) {
const first = head;
const second = head.next;
prev.next = second;
first.next = second.next;
second.next = first;
prev = first;
head = first.next;
}
return dummyHead.next;
};
时空复杂度
时间复杂度:1次遍历 O(n)
空间复杂度:常数变量 O(1)