算法学习记录(五十五)

156 阅读2分钟

问:

  1. N个加油站组成一个环形,给定两个长度都是N的非负数组oil和dis。oil[i]代表第i个加油站存多少单位个油,dis[i]代表第i个加油站到下个加油站需要多少单位个油。假设有一辆车初始油为空,从某个加油站出发,最终能回到这个加油站,那么这个加油站称为良好出发点,否则不是。请返回每个加油站是否为良好出发点。

  2. 一颗所有节点的值都不一样的二叉树原本是搜索二叉树,但是有两个节点调换了位置,使得这个二叉树不再是搜索二叉树,找到这两个错误节点并返回。

解: 1.

function checkStartPoint(oil, dis) {
    // 是否存在非负数
    let nonnegative = -1
    const res = []
    // 将oil和dis对应位置相减。
    // 此时oil表明需要多少油或者富裕多少油
    oil.forEach((item, idx) => {
        res.push(false)
        oil[idx] = item - dis[idx]
        if (oil[idx] >= 0 && nonnegative === -1) nonnegative = idx
    })
    // 都是负数,则没有良好出发点
    if (nonnegative === -1) return res
    // 存在一个正数出发点,那就从这个点开始
    let rest = 0
    let need = 0
    // 开始的加油站
    let start = nonnegative
    // 要去的加油站
    let end = nonnegative === oil.length - 1 ? 0 : nonnegative + 1
    // 初始油
    rest = oil[start]
    while (start !== end) {
        // 看能否走到下一个加油站
        if (rest + oil[end] >= 0) {
            // 能走过,把油结算一次
            rest += oil[end]
            end = end === oil.length - 1 ? 0 : end + 1
        } else {
            // 走不过,看看能否从开始加油站之前的加油站开始
            // [-2, 1, -3, 5, -1, -2, 2, 5, -4]
            while (start !== end) {
                // 如果start来到了数组第0个,那上一个加油站就是数组最后一个
                const pre = start === 0 ? oil[oil.length - 1] : oil[start - 1]
                // 如果上一个加油站是能到开始加油站的
                if (pre >= need) {
                    rest += pre
                    need = 0
                    start = start === 0 ? oil.length : start - 1
                    // 如果这个开始加油站可以带着足够多的rest冲过end,那么跳出循环
                    if (rest + oil[end] >= 0) {
                        break
                    }
                } else {
                    // 上一个加油站是负数,代表需要更多油才能过来,继续去找再上一个加油站
                    need += -pre
                    rest += pre
                    start = start === 0 ? oil.length - 1 : start - 1
                }
            }
            // 没找到能让车冲过end的开始加油站,直接结束
            if (rest + oil[end] < 0) return res
            // 否则就是找到了
        }
    }
    // 由start开始的加油站连同了
    if (start === end) {
        res[start] = true
    }
    // 已经知道了一个可以连通全局的加油站,那么只要在遍历一次,那些可以连通到该加油站的加油站都可以连同全局
    end = start === 0 ? oil.length - 1 : start - 1
    need = 0
    while (start !== end) {
        if (oil[end] >= need) {
            res[end] = true
        } else {
            need += -oil[end]
        }
        end = end === 0 ? oil.length - 1 : end - 1
    }
    return res
}
  1. 中序遍历,出现降序的时候有两种情况。一个是互换的节点是相邻节点,一个是不是相邻节点。
function findErrorNodes(head) {
    let firstFlag = false
    let preNode = null
    const res = [null, null]
    function getRes(node) {
        if (!node) return
        getRes(node.left)
        if (preNode) {
            if (node.value < preNode.value) {
                // 第一次降序的第一个节点
                if (!firstFlag) {
                    res[0] = preNode
                    firstFlag = true
                } else {
                    // 第二次降序的第二个节点
                    res[1] = node
                }
            }
        }
        preNode = node
        getRes(node.right)
    }
    getRes(head)
    return res
}