重排链表

264 阅读2分钟

正题

重排链表

给定一个单链表 L **的头节点 head ,单链表 L 表示为:

L0 → L1 → … → Ln - 1 → Ln

请将其重新排列后变为:

L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → …

不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

解析:

仔细分析一下,该题是要将链表重新排列,规则是将原链表的倒序,间隔插入到正序中

再详细的文字解释不如一张图来说明如何操作:

1.gif

原理:

  1. 找到链表的中间节点,得到新的链表 middle (middle 是 原链表的一部分)

  2. 将 middle 链表反转

  3. 将 middle 间隔插入原链表

  4. 删除 原链表后面的所有节点

寻找链表中间节点

之前有提到过如何寻找链表的中间节点,我们经常用到的方法就是快慢指针法,设 快指针 p 和 慢指针 middle, p 每次前进2格, middle 每次前进一格,当 p 遍历完毕时,middle 所指的节点即为原链表的中间节点。

    let p = head
    let middle = p
    while(p && p.next && p.next.next) {
        p = p.next.next
        middle = middle.next
    }

反转 Middle 链表

具体算法可以参考之前的文章 一张图说明链表反转

var transList = function (head) {
    let cur = head
  let pre = null
  while (cur) {
    const next = cur.next
    cur.next = pre
    pre = cur
    cur = next
  }
  return pre
}
middle = transList(middle.next)

穿插链表

需要注意 p 节点 和 m 节点是带有指针的,所以要预先缓存 p.nextm.next

 let m = middle
    while(m) {
        const pNext = p.next
        const mNext = m.next
        p.next = m
        p.next.next = pNext
        p = pNext
        m = mNext
    }

删除多余部分

   p.next = null

show code

/**
 * 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 {void} Do not return anything, modify head in-place instead.
 */

var transList = function (head) {
    let cur = head
  let pre = null
  while (cur) {
    const next = cur.next
    cur.next = pre
    pre = cur
    cur = next
  }
  return pre
}

var reorderList = function(head) {
    let p = head
    let middle = p
    while(p && p.next && p.next.next) {
        p = p.next.next
        middle = middle.next
    }
    middle = transList(middle.next)
    p = head
    let m = middle
    while(m) {
        const pNext = p.next
        const mNext = m.next
        p.next = m
        p.next.next = pNext
        p = pNext
        m = mNext
    }
    p.next = null
};

image.png

思路不难,难点在于每一步操作都需要有经验的积累,如果你不知道或者对找链表某个节点以及链表的反转不够敏感,这题将会有很多的阻碍困住你,如果你足够了解,把他们灵活运用就不难了。