算法学习记录(五十一)

142 阅读2分钟

问:

  1. 给定一棵二叉树的头结点head,已知所有节点值都不一样。返回其中最大符合搜索二叉树的最大拓扑结构的节点个数
  2. 给定一个长度为偶数的数组arr,长度记为2 * N,前N个当做左部分,后N个为右部分。arr就可以表示为[L1,L2,L3...LN,R1,R2,R3...RN]。将数组调整为[R1,L1,R2,L2,R3,L3...RN,LN],要求空间复杂度O(1)

解:

  1. 创建一个map,key是一个节点,value存放的是对于此节点来说,左右子树分别贡献了多少符合条件的节点。当递归来到一个节点的时候,遍历左子树的右边界,查询是否有不合符条件的节点,若有就记录这个节点。同样遍历右子树的左边界,查询是否有不符合条件的节点,有则记录。当获取到不符合条件的节点,意味着左右子树满足二叉搜索结构的路径走到不符合节点时就会断掉。所以左子树的右边界沿途节点的贡献值把不符合节点的贡献值减去。右子树的左边界沿途节点的贡献值把不符合节点的贡献值减去。这样就更新了左子树的贡献值和右子树的贡献值,存入map。用一个全局变量max去判断最大节点数即可。
function getMax(head) {
    const map = new Map()
    let max = 1
    function getRes(node) {
        if (!node) return
        getRes(node.left)
        getRes(node.right)
        let tempLeft = node.left
        let tempRight = node.right
        const breakLeft = {
            node: null,
            value: 0
        }
        const breakRight = {
            node: null,
            value: 0
        }
        // 判断左树的右边界是否有不满足条件的
        while (tempLeft) {
            if (tempLeft.value < node.value) {
                tempLeft = tempLeft.right
            } else {
                // 有某个节点不满足二叉搜索树
                breakLeft.node = tempLeft
                breakLeft.value = map.get(tempLeft).all
                map.delete(tempLeft)
                break
            }
        }
        // 判断右树的左边界是否有不满足条件的
        while (tempRight) {
            if (tempRight.value > node.value) {
                tempRight = tempRight.left
            } else {
                breakRight.node = tempRight
                breakRight.value = map.get(tempRight).all
                map.delete(tempRight)
                break
            }
        }
        if (tempLeft) {
            tempLeft = node.left
            while (tempLeft !== breakLeft.node) {
                const preValue = map.get(tempLeft)
                map.set(tempLeft, {
                    l: preValue.l,
                    r: preValue.r - breakLeft.value,
                    all: preValue.l + preValue.r - breakLeft.value + 1
                })
                tempLeft = tempLeft.right
            }
        }
        if (tempRight) {
            tempRight = node.right
            while (tempRight !== breakRight.node) {
                const preValue = map.get(tempRight)
                map.set(tempRight, {
                    l: preValue.l - breakRight.value,
                    r: preValue.r,
                    all: preValue.l + preValue.r - breakRight.value + 1
                })
                tempRight = tempRight.left
            }
        }
        const l = map.has(node.left) ? map.get(node.left).all : 0
        const r = map.has(node.right) ? map.get(node.right).all : 0
        map.set(node, {
            l,
            r,
            all: l + r + 1
        })
        max = Math.max(max, l + r + 1)
    }
    getRes(head)
    return max
}
  1. 完美洗牌算法
function shuffleCards(arr) {
    let handleLength = arr.length
    while (handleLength > 0) {
        // 剩余要处理的个数,最多是3的几次方 - 1
        const k = getK(handleLength)
        // 这一批处理多少个数
        const temp = 3 ** k - 1
        // 从何处开始处理
        const start = arr.length - handleLength
        const split = Math.floor(((arr.length - handleLength) + arr.length - 1) / 2)
        reverse(temp / 2 + start, split + temp / 2, split)

        wash(k, start, arr)
        handleLength -= temp
    }
    return arr
    function getK(length) {
        let k = 1
        while (3 ** (k + 1) - 1 < length) {
            k++
        }
        return k
    }
    function wash(k, start, arr) {
        let idx = 1
        while (idx <= k) {
            const cur = 3 ** (idx - 1) - 1 + start
            const info = {
                value: arr[cur],
                idx: cur
            }
            arr[info.idx] = null
            while (info.value) {
                const pos = getPosition(info.idx - start, 3 ** k -1) + start
                if (arr[pos]) {
                    const temp = arr[pos]
                    arr[pos] = info.value
                    debugger
                    info.value = temp
                    info.idx = pos
                } else {
                    arr[pos] = info.value
                    info.value = null
                    info.idx = -1
                }
            }
            idx++
        }
    }

    function reverse(left, right, split) {
        let l1 = left
        let r1 = split
        while (l1 < r1) {
            [arr[l1], arr[r1]] = [arr[r1], arr[l1]]
            l1++
            r1--
        }
        let l2 = split + 1
        let r2 = right
        while (l2 < r2) {
            [arr[l2], arr[r2]] = [arr[r2], arr[l2]]
            l2++
            r2--
        }
        let l3 = left
        let r3 = right
        while (l3 < r3) {
            [arr[l3], arr[r3]] = [arr[r3], arr[l3]]
            l3++
            r3--
        }
    }
    function getPosition(idx, n) {
        n = n / 2
        if (idx < n) {
            return 2 * idx + 1
        }
        return 2 * (idx - n)
    }
}