【BFS二叉树】113路径总和II

113路径总和 II

给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。

思路:

题目最终输出的是路径,因此用BFS遍历的时候,需要记录走到每个节点的路径;

又因为路径和是要等于某个目标值的,因此也需要记录目标和。

⇒ 走到每个节点时需要记录 该结点的路径路径和

⇒ BFS 里queue 记录 的节点 [ node , [ node.val],node.val]

function TreeNode(val, left, right) {
  this.val = val === undefined ? 0 : val
  this.left = left === undefined ? null : left
  this.right = right === undefined ? null : right
}

// 根据数组创建一颗树
const createTree = (arr) => {
  const len = arr.length
  if (len === 0) return null
  const root = new TreeNode(arr[0]) // 根节点
  const queue = [root] // 用于存储每一层的节点
  let i = 1 // 当前节点在数组中的索引
  while (i < len) {
    const node = queue.shift() // 取出当前层的第一个节点
    const leftVal = arr[i++] // 左子节点的值
    const rightVal = arr[i++] // 右子节点的值
    if (leftVal !== null) {
      const leftNode = new TreeNode(leftVal)
      node.left = leftNode
      queue.push(leftNode) // 将左子节点添加到队列中
    }
    if (rightVal !== null) {
      const rightNode = new TreeNode(rightVal)
      node.right = rightNode
      queue.push(rightNode) // 将右子节点添加到队列中
    }
  }
  return root
}

let arr = [5, 4, 8, 11, null, 13, 4, 7, 2, null, null, 5, 1]
let root = createTree(arr)
// console.log(root) // 输出树的结构

/**
 * @param {TreeNode} root
 * @param {number} targetSum
 * @return {number[][]}
 */
var pathSum = function (root, targetSum) {
  // 找出所有,遍历的时候记录路径,路径和,路径和用于判断是否满足条件
  let res = []
  if (!root) return res

  let queue = [[root,[root.val],root.val]]

  while (queue.length) {
    const [node,path,pathSum] = queue.shift()
    
    // 满足条件保存。
    if (node.left === null && node.right === null && pathSum === targetSum) {
      res.push(path)
    }
    
    // 将临近的节点加入queue
    if (node.left) {
      queue.push([node.left, path.concat([node.left.val]), pathSum + node.left.val])
    }
    if (node.right) {
      queue.push([node.right, path.concat([node.right.val]), pathSum + node.right.val])
    }
  }

  return res
}

注意:path.concat 返回的是数组,path.push返回的是数组的长度。

 console.log([5].push(3)) // 返回的是长度。
 console.log([5].concat(3)) // [5, 3]

 let list = [5]
 list.push(2)
 console.log(list) // 返回的是 [5,2]

二、二叉树标记将路径和中分的点

从根到叶子节点的通路上,有个节点可以把通路上的节点平分成两部分,将其标记,统计整棵树上的所有节点和减去标记节点的和

如图,绿色的即为标记的点,

在这里插入图片描述

节点3上边为 6+7=13,下边为11+2=13,因此将3标记

节点5上边为7,下边有4+3 = 7,因此标记

节点1上边为7+5+4 = 16,下边为16,标记

思路:

BFS遍历每个节点,如果某个节点是所在路径的中间点,那么该节点的前缀和是所在路径和-该节点的值后剩余数的 一半,因此对于每个节点来说,都需要记录前缀和、路径和以及该节点的值。

因为树上可能会出现值一样的不同节点,因此visitedMap 需要保存的key是节点,而不能是节点的值。

function TreeNode(val, left, right) {
  this.val = val === undefined ? 0 : val
  this.left = left === undefined ? null : left
  this.right = right === undefined ? null : right
}

// 根据数组创建一颗树
const createTree = (arr) => {
  const len = arr.length
  if (len === 0) return null
  const root = new TreeNode(arr[0]) // 根节点
  const queue = [root] // 用于存储每一层的节点
  let i = 1 // 当前节点在数组中的索引
  while (i < len) {
    const node = queue.shift() // 取出当前层的第一个节点
    const leftVal = arr[i++] // 左子节点的值
    const rightVal = arr[i++] // 右子节点的值
    if (leftVal !== null) {
      const leftNode = new TreeNode(leftVal)
      node.left = leftNode
      queue.push(leftNode) // 将左子节点添加到队列中
    }
    if (rightVal !== null) {
      const rightNode = new TreeNode(rightVal)
      node.right = rightNode
      queue.push(rightNode) // 将右子节点添加到队列中
    }
  }
  return root
}

let arr = [7, 6, 5, 3, null, 4, null, 11, null, 1, 3, 2, null, 16, null]
let root = createTree(arr)

const bisectTreePath = (root) => {
  const queue = [[root, [root], root.val, [root.val]]]
  
  // 因为可能出现相同值的不同结点,如果map值存放值,就可能会遗漏。因此map的key存放树节点。
  let markedMap = new Map()

  const res = []

  while (queue.length > 0) {
    const [node, path, pathSum, pre] = queue.shift()
    markedMap.set(node, false)
    
    // 遇到叶子结点将结果保存。
    if (node.left === null && node.right === null) {
      res.push([path, pathSum, pre])
    }

    if (node.left !== null) {
      queue.push([
        node.left,
        path.concat(node.left),
        pathSum + node.left.val,
        pre.concat(pre.at(-1) + node.left.val)
      ])
    }
    if (node.right !== null) {
      queue.push([
        node.right,
        path.concat(node.right),
        pathSum + node.right.val,
        pre.concat(pre.at(-1) + node.right.val)
      ])
    }
  }

  for (let i = 0; i < res.length; i++) {
    const [path, pathSum, pre] = res[i]
    // console.log(path[0].val,11)
    for (let j = 0; j < pre.length - 1; j++) {
      if (
        pre[j] * 2 + path[j + 1].val === pathSum &&
        !markedMap.get(path[j + 1])
      ) {
        markedMap.set(path[j + 1], true)
      }
    }
  }

  // 遍历markedMap
  let sum = 0
  for (let [key, value] of markedMap) {
    if (value === false) {
      sum += key.val
    }
  }
  return sum
}

console.log(bisectTreePath(root))

最近更新

  1. TCP协议是安全的吗?

    2024-03-14 00:36:04       14 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-03-14 00:36:04       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-03-14 00:36:04       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-03-14 00:36:04       18 阅读

热门阅读

  1. js--构造函数

    2024-03-14 00:36:04       22 阅读
  2. 前端各框架、优缺点及应用场景

    2024-03-14 00:36:04       20 阅读
  3. Python互斥锁实例(包含超时解锁)

    2024-03-14 00:36:04       18 阅读
  4. 深入理解Spring的ApplicationContext:案例详解与应用

    2024-03-14 00:36:04       20 阅读
  5. js小知识

    2024-03-14 00:36:04       21 阅读
  6. 子查询

    2024-03-14 00:36:04       22 阅读
  7. JenKins 中的new Item各个选项应该怎选择

    2024-03-14 00:36:04       18 阅读
  8. HAProxy适配openGauss使用指导书

    2024-03-14 00:36:04       21 阅读
  9. 在Rust中,探索word到pdf的转换

    2024-03-14 00:36:04       22 阅读
  10. 英语阅读挑战

    2024-03-14 00:36:04       21 阅读
  11. 华为机试题-字符串压缩

    2024-03-14 00:36:04       19 阅读
  12. 测开面经学习笔记

    2024-03-14 00:36:04       17 阅读
  13. C++进阶学习

    2024-03-14 00:36:04       21 阅读