算法学习记录(八)

152 阅读2分钟

链表

问:

  1. 如何判断是否为回文链表
  2. 给定一个链表的head,和一个指定值target,将单向链表按target调整为左边都是小于target,中间等于target、右边大于target的顺序
  3. 一个链表中,每个节点都有一个rand指针,这个指针指向链表内任一节点或者null,如何完全复制这个链表

解:

  1. 快慢指针解法,快指针走两个位置,慢指针走一个位置,当快指针走完,慢指针就在中点,知道中点位置就可以比较了。
function isPalindrome(head) {
    let slowIdx = head
    let quickIdx = head
    let midIdx = null
    while (quickIdx.next) {
        slowIdx = slowIdx.next
        quickIdx = quickIdx.next.next ?? quickIdx.next
    }
    midIdx = slowIdx
    slowIdx = head
    // 反转后半部链表,reverseList方法自行实现
    const tempNode = reverseList(midIdx)
    while (slowIdx !== midIdx) {
        if (slowIdx === quickIdx) {
            slowIdx = slowIdx.next
            quickIdx = quickIdx.next
        } else {
            reverseList(tempNode)
            return false
        }
    }
    reverseList(tempNode)
    return true
}

2.划分为三个链,最后把小于链、等于链、大于链连接起来(如果存在的话)

    function divisionArea(head, target) {
        let smStart = null
        let smEnd = null
        let eqStart = null
        let eqEnd = null
        let lgStart = null
        let lgEnd = null
        let curNode = head
        while (curNode) {
            if (curNode.value < target) {
                smStart = smStart ?? curNode
                if (smEnd) smEnd.next = curNode
                smEnd = curNode
            }
            if (curNode.value === target) {
                eqStart = eqStart ?? curNode
                if (eqEnd) eqEnd.next = curNode
                eqEnd = curNode
            }
            if (curNode.value > target) {
                lgStart = lgStart ?? curNode
                if (lgEnd) lgEnd.next = curNode
                lgEnd = curNode
            }
            curNode = curNode.next
        }
        lgEnd && (lgEnd.next = null)
        smEnd && (smEnd.next = eqStart ?? lgStart)
        eqEnd && (eqEnd.next = lgStart)
        return smStart ?? eqStart ?? lgStart
    }

3.在原链表上按顺序复制一份,这样复制rand属性时,就可以根据原节点的rand找到复制节点应该对应的rand节点,然后拆分链表即可

    // 1 - 2 - 3
    function copyLinkedList(head) {
        let current = head
        let res = null
        // 复制next属性
        while (current) {
            // 复制节点
            const copyNode = new Node(current.value)
            // 将复制的节点,放到正常节点后面
            const temp = current.next
            current.next = copyNode
            copyNode.next = temp
            current = temp
        }
        current = head
        // 最终为 1 - 1' - 2 - 2' - 3 - 3'
        // 复制rand属性
        while (current) {
            const copyNode = current.next
            // 譬如当前节点是1,复制节点是1'。 1的rand指向3,那么1'的rand指向3的next(因为3和3'是有序的)
            copyNode.rand = current.rand.next
            current = current.next.next
        }
        current = head
        // 分离链表
        while (current) {
            const temp = current.next
            res ??= temp
            current.next = current.next.next
            current = temp
        }
        return res
    }