024两两交换链表中的节点(JS)

211 阅读2分钟

两两交换链表中的节点

Category Difficulty Likes Dislikes
algorithms Medium (61.26%) 253 -
Tags

linked-list

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) {
    
};


image-20190806090835996

红是交换前,蓝是交换后

两两交换时,有变动的是三个元素,大家很容易忽略原本的prev.next的由原本的a变为现在的b

所以我们需要三个变量来进行两两交换

  1. prev的下一个节点改为bprev.next = b
  2. a的下一个节点变为原本b的下一个节点:a.next = b.next
  3. b的下一个节点变为ab.next = a
[prev.next, b.next, a.next] = [b, a, b.next]

第一次交换的时候ab指的就是链表的首位和次位,那么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

现在我们要开始思考循环的问题了

image-20190806091518934

前面的红色是第一次交换,蓝色是交换后,后面的红色是下一次开始交换

const ret = new ListNode()
ret.next = head
let [prev, a, b] = [ret, null, null]
while(/*条件*/){
	// 循环
}
return ret.next
  • 循环

因为prev,ab是连续的,所以我们只要让prev跳到下次循环的位置,ab的位置就很明确了

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给的

  • aprev.next
  • bprev.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行要加;