递归法的递归函数何时需要返回值

在处理树这类问题的时候我们常常会用到递归法,众所周知,递归法有三部曲,其中第一步就是确定递归函数的参数和返回值以及类型,我们如何判断哪些情况需要返回值,哪些情况递归函数不需要返回值呢?

判断递归函数是否需要返回值主要基于以下几个关键原则:

基于问题的目标性质

需要返回值的情况有:

  • 查找类的问题: 需要找到某个特定的节点或者路径
  • 判断类的问题: 需要判断这棵树是否满足某种性质
  • 计算类的问题: 需要计算并向上传递某个值
  • 提前终止: 一旦找到答案就可以停止搜索,立即返回

不需要返回值的情况有:

  • 遍历类的问题: 需要遍历所有节点
  • 收集类的问题: 需要收集所有满足条件的节点或者路径
  • 修改类的问题: 直接修改树的结构或者节点值
  • 完整的搜索: 必须要遍历整棵树才能获得完整答案

需要返回值的典型例子

leetcode112 - 路径和:判断是否存在一条路径和等于给定的目标和

js 复制代码
/**
 * @param {TreeNode} root
 * @param {number} targetSum
 * @return {boolean}
 */
const hasPathSum = function(root, targetSum) {
    const traversal = (node, count/**递归参数为节点以及边和 */) => {
    //递归终止条件
        if(!node.left && !node.right && count == 0) return true;
        if(!node.left && !node.right) return false;
        if(node.left){
            count -= node.left.val; // 采用递减的方式
            if(traversal(node.left, count)) return true;
            count += node.left.val; // 回溯
        }
        if(node.right){
            count -= node.right.val;
            if(traversal(node.right, count)) return true;
            count += node.right.val;
        }
        return false;
    }
    if(!root) return false;
    return traversal(root, targetSum - root.val);
}

leetcode104 - 二叉树的最大深度:给定一个二叉树,找出其最大深度

js 复制代码
const maxDepth = function(root) {
  if(!root){
    return 0;
  }
  let maxLeft = maxDepth(root.left);
  let maxRight = maxDepth(root.right);
  return Math.max(maxLeft, maxRight) + 1;
};

以上两道题目都需要返回值,因为它们都需要找到一个特定的节点或者路径,或者需要计算并向上传递某个值。

不需要返回值的典型例子

leetcode113 - 路径总和II:给定一个二叉树和一个目标和,找到所有从根节点到叶子节点路径总和等于给定目标和的路径。

js 复制代码
var pathSum = function(root, sum) {
    let res = [];
    let path = [];
    const dfs = (node, count, pathList) => {
        if(!node.left && !node.right && count === 0) {
            res.push([...pathList]);
            return;
        }
        // 如果没找到符合条件的路径直接返回
        if(!node.left && !node.right) return;
        if(node.left){
            count -= node.left.val; // 
            pathList.push(node.left.val); // 
            dfs(node.left, count, pathList);
            count += node.left.val;// 回溯
            pathList.pop(); // 回溯
        }
        if(node.right) {
            count -= node.right.val;
            pathList.push(node.right.val);
            dfs(node.right, count, pathList);
            count += node.right.val;
            pathList.pop();
        }
        
    }
    if(!root) return [];
    path.push(root.val);
    dfs(root, sum - root.val, path);
    return res;
}

leetcode257 - 二叉树的所有路径:给定一个二叉树,返回所有从根节点到叶子节点的路径。

js 复制代码
const binaryTreePaths = function(root) {
    if(!root) return [];
    const res = [];
    const path = [];
    const dfs = (node) => {
        // 将当前节点加入路径
        path.push(node.val);
        // 如果当前节点是叶子节点,将路径加入结果数组
        if(!node.left && !node.right) {
            res.push(path.join('->'));
        } else {
            // 如果当前节点不是叶子节点,递归遍历左子树和右子树
            node.left && dfs(node.left);
            node.right && dfs(node.right);
        }
        // 回溯,将当前节点从路径中移除
        path.pop();
    }
    dfs(root);
    return res;
}

以上两道题目都不需要返回值,因为它们都需要遍历所有节点,并且需要收集所有满足条件的节点或者路径。

判断决策树

text 复制代码
问题类型判断
├── 是否需要提前终止?
│   ├── 是 → 需要返回值(如:路径和判断、查找节点)
│   └── 否 → 继续判断
├── 是否需要向上传递信息?
│   ├── 是 → 需要返回值(如:计算深度、判断平衡)
│   └── 否 → 继续判断
├── 是否需要收集所有结果?
│   ├── 是 → 不需要返回值(如:所有路径、层序遍历)
│   └── 否 → 需要返回值
└── 是否直接修改全局状态?
    ├── 是 → 不需要返回值(如:翻转树、修改节点值)
    └── 否 → 需要返回值

总结

  • 先明确问题目标 :是找一个答案还是找所有答案
  • 分析搜索特性 :能否提前终止还是必须完整遍历
  • 考虑信息流向 :是否需要子树向父节点传递信息
  • 确定状态管理 :使用局部变量还是全局变量收集结果

通过这些原则,可以在设计递归函数时快速判断是否需要返回值。

相关推荐
贾全2 分钟前
第十章:HIL-SERL 真实机器人训练实战
人工智能·深度学习·算法·机器学习·机器人
GIS小天17 分钟前
AI+预测3D新模型百十个定位预测+胆码预测+去和尾2025年7月4日第128弹
人工智能·算法·机器学习·彩票
满分观察网友z35 分钟前
开发者的“右”眼:一个树问题如何拯救我的UI设计(199. 二叉树的右视图)
算法
森焱森2 小时前
无人机三轴稳定化控制(1)____飞机的稳定控制逻辑
c语言·单片机·算法·无人机
循环过三天2 小时前
3-1 PID算法改进(积分部分)
笔记·stm32·单片机·学习·算法·pid
闪电麦坤952 小时前
数据结构:二维数组(2D Arrays)
数据结构·算法
凌肖战3 小时前
力扣网C语言编程题:快慢指针来解决 “寻找重复数”
c语言·算法·leetcode
埃菲尔铁塔_CV算法3 小时前
基于 TOF 图像高频信息恢复 RGB 图像的原理、应用与实现
人工智能·深度学习·数码相机·算法·目标检测·计算机视觉
NAGNIP4 小时前
一文搞懂FlashAttention怎么提升速度的?
人工智能·算法