前言
理解递归
有一句编程的至理名言是这样的:
“要理解递归,首先要理解递归”递归是一种解决问题的方法,它从解决问题的各个小部分开始,直到解决最初的大问题。递归通常涉及函数调用自身。每个递归函数都必须有基线条件,即一个不再递归调用的条件(停止点),以防止无限递归。
递归计算一个数的阶乘
数n的阶乘,定义为n!,表示从1到n的整数的乘积。可以将步骤定义如下:(n) * (n-1) * (n-2) * (n-3)*...*1.
function factorialIterative(number) {
if(number < 0) return undefined;
let total = 1;
for(let n = number; n>1; n--){
total = total * n;
}
return total;
}
console.log(factorialIterative(5)); // 120
递归阶乘
// factorial(5) = 5 * factorial(4);我们可以用5 * 4!来计算5!
// factorial(5) = 5 * (4 * factorial(3));我们需要计算子问题4!,它可以用4 * 3!来计算
// factorial(5) = 5 * 4 * (3 * factorial(2));我们需要子计算问题3!,它可以用3 * 2!来计算
// factorial(5) = 5 * 4 * 3 (2 * factorial(1));我们需要计算子问题2!,它可以用2 * 1!来计算
// factorial(5) = 5 * 4 * 3 * 2 * (1);我们需要计算子问题1!。
function factorial(n) {
if(n === 1 || n === 0){ // 基线条件
return 1;
}
return n * factorial(n - 1); // 递归调用
}
console.log(factorial(5)); // 120
题目描述
给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。如果存在,返回 true ;否则,返回 false 。
叶子节点 是指没有子节点的节点。
示例1
输入:root = [5,4,8,11,null,13,4,7,2,null,null,null,1], targetSum = 22
输出:true
解释:等于目标和的根节点到叶节点路径如上图所示。
示例2
输入:root = [1,2,3], targetSum = 5
输出:false
解释:树中存在两条根节点到叶子节点的路径:
(1 --> 2): 和为 3
(1 --> 3): 和为 4
不存在 sum = 5 的根节点到叶子节点的路径。
示例3
输入: root = [], targetSum = 0
输出: false
解释: 由于树是空的,所以不存在根节点到叶子节点的路径。
解题思路
1.我们的最终目的是找到一个从根节点出发的数值累加到某一个叶子节点的数值和等于targetSum。 2.因此,我们可以将targetSum减去当前节点的值,然后传递给当前节点的子节点 3.如何当前节点没有子节点,就要判断targetSum是否为0,如果为0,就证明我们至少有一条路径 4.如果没有一个到达叶子节点为零的情况,证明没有符合条件的路径
代码
/**
* 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 {boolean}
*/
var hasPathSum = function(root, targetSum) {
// 如果根节点为空,就返回false
if(!root) return false;
// 当前节点如果没有左节点也没有右节点,就去判断当前节点的值是否等于targetSum
if(!root.left && !root.right) return targetSum === root.val; // 基线条件
// 将targetSum节点的值减去当前节点的值,然后传递给当前节点的子节点
targetSum -= root.val;
// targetSum的值减去根节点的值后去递归调用根节点的左孩子或者右孩子
return hasPathSum(root.left, targetSum) || hasPathSum(root.right, targetSum);
};