算法学习记录(八十七)

89 阅读1分钟

143. 重排链表

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

L0 → L1 → … → Ln - 1 → Ln 请将其重新排列后变为:

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

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

image.png

解:

可以看到前半部分链表是正序,后半部分链表是逆序。所以需要把后半部分链表反转再和前半部分链表依次结合。

  1. 快慢指针找中点
  2. 以中点为界限分离两个链表
  3. 把后面的链表反转
  4. 慢指针指向前链表,快指针指向后链表。此时快慢指针不再有快慢的含义,只是普通指针。
  5. 以前-后-前-后的形式合并链表
const reorderList = function(head) {
    // 反转链表
    const reverseList = (node) => {
        let cur = node 
        let pre = null 
        while (cur) {
            const temp = cur.next 
            cur.next = pre 
            pre = cur 
            cur = temp
        }
        return pre
    }
    let quickNode = head 
    let slowNode = head
    // 中点的前一个节点,用于分离前后链表
    let pre = null
    while (quickNode.next) {
        pre = slowNode
        slowNode = slowNode.next 
        quickNode = quickNode.next.next ?? quickNode.next
    }
    // 避免后续合并链表时循环引用
    if (quickNode === slowNode) return head
    // 分离链表
    pre.next = null 
    quickNode = reverseList(slowNode)
    slowNode = head
    let resNode = null
    while (slowNode) {
        if (!resNode) {
            resNode = slowNode
        } else {
            resNode.next = slowNode
            resNode = resNode.next
        }
        slowNode = slowNode.next
        resNode.next = quickNode
        quickNode = quickNode.next
        resNode = resNode.next
    }
    return head
};