【LeetCode】两题一解 - 路径总和 & 求根节点到叶节点数字之和 - 递归 - 双队列

544 阅读3分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

本文已参与「掘力星计划」,赢取创作大礼包,挑战创作激励金。

关于树的结构与遍历可以看我之前的博文:二叉树的结构与遍历,这里说了结构,与遍历方式,有递归和非递归的遍历方式,前序,中序,后序遍历方式的多种实现,是做树类的算法题的基础~ 还有刚刚发布的层序遍历博文二叉树的层序遍历 - 广度优先遍历BFS

112. 路径总和

给你二叉树的根节点 root 和一个表示目标和的整数 targetSum ,判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum

【解法一】递归

使用递归来做这题就变成简单题了~

思路就是: 从根节点开始遍历整颗树,将目标和整数减去当前节点的值(targetSum - root.val),然后递归调用... 直到遇到叶子节点,此时判断是否符合条件,符合条件就返回true,否则就返回false

具体的代码编写和思路直接看我代码上的注释吧,写的很详细~

var hasPathSum = function(root, targetSum) {
    // 节点不存在 返回false
    if(!root) return false
    // 左右子树都不存在,说明是叶子节点,判断是否符合条件
    if(!root.left && !root.right) return targetSum === root.val
    
    // 到这里就是:节点存在,左右子树存在一个或者都存在,也就是内部节点
    // 遍历左右子树,更新总和为 总和删除当前节点的值
    return hasPathSum(root.left, targetSum - root.val) || hasPathSum(root.right, targetSum - root.val)
};

在这里插入图片描述

【解法二】BFS - 双队列

如果不能使用递归,那我们就要使用队列来模拟了,这里我们使用两个队列,一个用来存储节点,一个用来存储节点的总和

var hasPathSum = function(root, targetSum) {
    if(!root) return false
    // 创建两个队列
    // 用来存储节点
    let nodeQue = []
    // 用来存储根节点到这个节点的总和
    let valQue = []

    // 先将根节点入队列
    nodeQue.unshift(root)
    valQue.unshift(root.val)

    while(nodeQue.length > 0){
        // 将队头元素取出来得到节点root和值temp
        let root = nodeQue.pop()
        let temp = valQue.pop()

        // 如果这个节点是叶子节点(没有左右孩子)
        if(!root.left && !root.right){
            // 如何符合要求返回true 并 退出函数
            if(temp === targetSum) return true
            // 不满足要求 下面的都不会满足,就进行下一轮循环了
        }
        // 有左孩子就进来
        if(root.left){
            // 左孩子进队列
            nodeQue.unshift(root.left)
            // 保存此时路径总和
            valQue.unshift(root.left.val + temp)
        }
        // 有右孩子就进来
        if(root.right){
            // 右孩子进队列
            nodeQue.unshift(root.right)
            // 保存此时路径总和
            valQue.unshift(root.right.val + temp)
        }
    }
    // 循环走完都没有返回true就说明没有符合要求的路径总和
    return false

};

在这里插入图片描述

129. 求根节点到叶节点数字之和

给你一个二叉树的根节点 root ,树中每个节点都存放有一个 0 到 9 之间的数字。 每条从根节点到叶节点的路径都代表一个数字: 例如,从根节点到叶节点的路径 1 -> 2 -> 3 表示数字 123 。 计算从根节点到叶节点生成的 所有数字之和 。

这题和112题的解法一模一样

【解法一】BFS - 双队列

var sumNumbers = function(root) {
    let nodeQue = []
    let valQue = []
    let result = 0
    nodeQue.unshift(root)
    valQue.unshift(root.val)
    while(nodeQue.length > 0){
        let root = nodeQue.pop()
        let temp = valQue.pop()
        if(!root.left && !root.right) {
            result += temp
        }
        if(root.left){
            nodeQue.unshift(root.left)
            valQue.unshift(root.left.val + temp * 10)
        }
        if(root.right){
            nodeQue.unshift(root.right)
            valQue.unshift(root.right.val + temp * 10)
        }
    }
    return result
};

在这里插入图片描述

【解法二】递归

var sumNumbers = function(root) {   
    return dfs(root, 0)
};

function dfs(root, prevSum){
    // 节点不存在直接返回0
    if(!root) return 0
    // 根节点到当前节点数字之和
    let sum = prevSum * 10 + root.val

    // 如果是叶子节点,就返回sum
    if(!root.left && !root.right) return sum
    // 不是叶子节点,就递归,并把当前的和传给孩子节点
    return dfs(root.left, sum) + dfs(root.right, sum)
}