两两交换链表中的节点
| Category | Difficulty | Likes | Dislikes |
|---|---|---|---|
| algorithms | Medium (61.26%) | 253 | - |
Tags
Companies
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
示例:
给定 1->2->3->4, 你应该返回 2->1->4->3.
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} head
* @return {ListNode}
*/
var swapPairs = function(head) {
};

红是交换前,蓝是交换后
两两交换时,有变动的是三个元素,大家很容易忽略原本的prev.next的由原本的a变为现在的b。
所以我们需要三个变量来进行两两交换
prev的下一个节点改为b:prev.next = ba的下一个节点变为原本b的下一个节点:a.next = b.nextb的下一个节点变为a:b.next = a
[prev.next, b.next, a.next] = [b, a, b.next]
第一次交换的时候a和b指的就是链表的首位和次位,那么prev就无处表示,为了后续循环的统一,我们在交换的一开始,就在链表的头添加一个新结点
const prev = new ListNode()
prev.next = head
这三个指针是移动的,所以我们需要一个变量ret作为头节点,那我们把上面的代码改成ret,最后返回ret.next
const ret = new ListNode()
ret.next = head
let [prev, a, b] = [ret, null, null]
// 最终返回
return ret.next
现在我们要开始思考循环的问题了

前面的红色是第一次交换,蓝色是交换后,后面的红色是下一次开始交换
const ret = new ListNode()
ret.next = head
let [prev, a, b] = [ret, null, null]
while(/*条件*/){
// 循环
}
return ret.next
- 循环
因为prev,a和b是连续的,所以我们只要让prev跳到下次循环的位置,a和b的位置就很明确了
a = prev.next
b = a.next
注意上面的图,在交换后,prev的位置就是原本a的位置
while(/*条件*/){
a = prev.next
b = a.next;
[prev.next, b.next, a.next] = [b, a, b.next]
prev = a
}
- 条件
我们知道下一次循环的变量赋值都是由prev给的
a:prev.nextb:prev.next.next
如果后面只剩一个,即没有b,我们也是不用交换的,所以判断条件是
while(prev.next && prev.next.next)
最终的代码就是
var swapPairs = function (head) {
const ret = new ListNode()
ret.next = head
let [prev, a, b] = [ret, null, null]
while (prev.next && prev.next.next) {
a = prev.next
b = a.next;
[prev.next, b.next, a.next] = [b, a, b.next]
prev = a
}
return ret.next
};
记得代码第7行要加
;