113.路径总和2

/**
 * Definition for a binary tree node.
 * function TreeNode(val, left, right) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.left = (left===undefined ? null : left)
 *     this.right = (right===undefined ? null : right)
 * }
 */
/**
 * @param {TreeNode} root
 * @param {number} targetSum
 * @return {number[][]}
 */
var pathSum = function (root, targetSum) {
    let res = []

    // 深度优先遍历
    function deepOrder(root, target, pathNodes) {
        // 注意需要浅拷贝,否则同一个数组内存地址相同,最后pathNodes是全部节点
        let nodes = Array.from(pathNodes || [])

        if (!root) {
            return
        }
        // 路径上的节点
        nodes.push(root.val)

        // 找到与差值相同的叶子节点
        if (root.left === null && root.right === null && root.val === target) {
            res.push(nodes)
            return
        }

        // 继续往下找差值
        deepOrder(root.left, target - root.val, nodes)
        deepOrder(root.right, target - root.val, nodes)
    }

    deepOrder(root, targetSum)
    return res
};

/**
 * @param {TreeNode} root
 * @param {number} targetSum
 * @return {number[][]}
 */
var pathSum = function (root, targetSum) {
    if (!root) {
        return []
    }
    // 使用广度优先遍历+哈希表记录每个节点的父节点方便回溯
    let queue = [] // 每一层的节点
    queue.push(root)

    let sumQueue = [] // 路径sum队列
    sumQueue.push(root.val) // 刚开始经过root的路径和

    let pathLastNodes = [] // 每一条符合targetSum的最后一个节点集合

    let map = new Map() // key是节点,value是父节点
    map.set(root, null) // 根节点的父节点为null

    while (queue.length) {
        let len = queue.length // 当前层的节点数
        for (let i = 0; i < len; i++) {
            let node = queue.shift() // 当前节点
            let sum = sumQueue.shift() // 当前节点的路径和
            if (node.left === null && node.right === null && sum === targetSum) {
                pathLastNodes.push(node)
            }

            if (node.left) {
                queue.push(node.left)
                map.set(node.left, node) // 记录父节点
                sumQueue.push(sum + node.left.val) // 访问左节点后的路径和
            }
            if (node.right) {
                queue.push(node.right)
                map.set(node.right, node) // 记录父节点
                sumQueue.push(sum + node.right.val) // 访问右节点的路径和
            }
        }
    }

    // console.log(pathLastNodes)
    // map记录了每个节点的父节点,我们可以进行回溯,找出从叶子节点到根节点的整个path
    let res = []
    for (let i = 0; i < pathLastNodes.length; i++) {
        let path = []
        let node = pathLastNodes[i]
        // 根节点的父节点是null,遍历到根节点停止循环
        while (node !== null) {
            path.unshift(node.val) // 从前面插入
            node = map.get(node)
        }
        res.push(path)
    }

    return res
}