【算法通关】二叉树中的深搜:DFS 递归解题套路

文章目录

    • [1. 计算布尔二叉树的值](#1. 计算布尔二叉树的值)
    • [2. 求根节点到叶节点数字之和](#2. 求根节点到叶节点数字之和)
    • [3. 二叉树剪枝](#3. 二叉树剪枝)
    • [4. 验证二叉搜索树](#4. 验证二叉搜索树)
  • 深度优先遍历(DFS,全称为 Depth First Traversal),是树或者图这类数据结构中常用的一种遍历算法。这个算法会尽可能深地搜索树或者图的分支,直到一条路径上的所有节点都被遍历完毕,然后再回溯到上一层,继续找一条路遍历。

  • 在二叉树中,常见的深度优先遍历为:前序遍历、中序遍历以及后序遍历。

  • 因为树的定义本身就是递归定义,因此采用递归的方法去实现树的三种遍历不仅容易理解而且代码很简洁。并且前中后序三种遍历的唯一区别就是访问根节点的时机不同。


1. 计算布尔二叉树的值

题目链接:2331. 计算布尔二叉树的值

题目描述:

算法原理:递归

这道题的核心是自底向上递归计算完整二叉树的布尔运算值,本质是对二叉树的后序遍历应用。

1. 问题拆解:

  • 叶子节点 :值为 0(False)或 1(True),直接返回对应的布尔值。
  • 非叶子节点 :值为 2(OR)或 3(AND),需要先计算左右两个子节点的值,再用当前节点的运算符对两个子结果进行逻辑运算。

2. 递归逻辑:

  • 终止条件 :如果当前节点是叶子节点(无左右子节点),直接将节点值转换为布尔值返回(0→False1→True)。
  • 递归步骤
    • 递归计算左子树的布尔结果。
    • 递归计算右子树的布尔结果。
    • 根据当前节点的运算符:
      • 若为 2(OR):返回 左子结果 || 右子结果
      • 若为 3(AND):返回 左子结果 && 右子结果
  • 最终结果:根节点的递归返回值即为整棵树的布尔运算结果。

示例代码:

java 复制代码
class Solution {
    public boolean evaluateTree(TreeNode root) {
        
        if(root.left == null) return root.val == 0 ? false : true;

        boolean left = evaluateTree(root.left);
        boolean right = evaluateTree(root.right);

        return root.val == 2 ? left | right : left & right;
    }
}

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

题目链接:129. 求根节点到叶节点数字之和

题目描述:

算法原理:递归

这道题的核心是遍历所有根到叶子的路径,把每条路径拼接成数字并求和 ,本质是对二叉树做带状态的深度优先遍历(DFS)

1. 问题拆解

  • 每条从根到叶子的路径,代表一个十进制数:
    • 路径上的节点值依次作为数字的高位到低位。
    • 例如:1 → 2 → 3 对应 123,计算方式是 1 * 100 + 2 * 10 + 3
  • 目标:把所有这样的路径数字累加起来。

2. 递归逻辑

  • 状态传递 :递归函数需要携带「当前路径已经拼接出的数字」这个状态,从根节点向下传递。
    • 进入当前节点时,新的数字 = 上一层传递的数字 * 10 + 当前节点的值。
  • 终止条件:如果当前节点是叶子节点(无左右子节点),就把当前拼接好的数字加入总和。
  • 递归步骤
    • 如果当前节点有左子树,就带着更新后的数字递归左子树。
    • 如果当前节点有右子树,就带着更新后的数字递归右子树。
  • 最终结果:所有叶子节点处的数字之和,就是题目要求的总和。

示例代码:

java 复制代码
class Solution {
    public int sumNumbers(TreeNode root) {

        return dfs(root,0);

    }

    public int dfs(TreeNode root,int num){
        
        num = num * 10 + root.val;
        if(root.left == null && root.right == null) return num;

        int ret = 0;
        if(root.left !=  null) ret += dfs(root.left,num);
        if(root.right != null) ret += dfs(root.right,num);
        return ret;

    }
}

3. 二叉树剪枝

题目链接:814. 二叉树剪枝

题目描述:

算法原理:递归

这道题的核心是自底向上递归修剪二叉树 ,本质是后序遍历的应用,目标是移除所有不包含 1 的子树。

1. 问题拆解

  • 子树定义:节点本身 + 所有后代节点。
  • 修剪规则:如果一个子树完全不包含 1 (即节点自身为 0,且左右子树也都不含 1),就将该子树移除(置为 null);否则保留。

2. 递归逻辑

  • 终止条件 :如果当前节点是 null,直接返回 null
  • 递归步骤
    • 先递归处理左子树,得到修剪后的左孩子。
    • 再递归处理右子树,得到修剪后的右孩子。
    • 更新当前节点的左右孩子为修剪后的结果。
  • 判断是否保留当前节点
    • 如果当前节点的值是 1必须保留,直接返回当前节点。
    • 如果当前节点的值是 0
      • 若左右子树都为 null(说明整个子树不含 1):返回 null(移除该子树)。
      • 否则:返回当前节点(因为子树中包含 1,需要保留)。
  • 最终结果 :根节点经过递归修剪后,就是移除了所有不含 1 子树的二叉树。

示例代码:

java 复制代码
class Solution {
    public TreeNode pruneTree(TreeNode root) {
        
        if(root == null) return null;
        
        TreeNode left = pruneTree(root.left);
        TreeNode right = pruneTree(root.right);
        root.left = left;
        root.right = right;

        if(root.left == null && root.right == null && root.val == 0) return null;
        return root;
    }
}

4. 验证二叉搜索树

题目链接:98. 验证二叉搜索树

题目描述:

算法原理:递归

这道题的核心是递归验证每个节点是否在合法的数值区间内,本质是利用二叉搜索树(BST)的定义,对每个节点约束其取值范围。

1. 问题拆解

有效BST的核心约束:

  • 左子树所有节点值 严格小于 当前节点值;
  • 右子树所有节点值 严格大于 当前节点值;
  • 左右子树本身也必须是有效BST。

直接判断"左孩子 < 根 < 右孩子"是不够的,还需要保证左子树的最大值 < 根,右子树的最小值 > 根,因此需要传递区间约束

2. 递归逻辑

  • 终止条件 :如果当前节点是 null(空树),直接返回 true(空树天然是BST)。
  • 区间约束传递
    • 递归函数需要额外携带两个参数:low(当前节点允许的最小值,开区间)和 high(当前节点允许的最大值,开区间)。
    • 根节点初始时,low 为负无穷,high 为正无穷。
  • 当前节点校验
    • 如果当前节点值 ≤ low 或 ≥ high → 违反BST规则,返回 false
  • 递归校验子树
    • 校验左子树:左子树的最大值必须 < 当前节点值,因此左子树的 high 约束为当前节点值,low 继承父节点的 low
    • 校验右子树:右子树的最小值必须 > 当前节点值,因此右子树的 low 约束为当前节点值,high 继承父节点的 high
    • 只有左右子树都返回 true,当前节点所在子树才是有效BST。
  • 最终结果:根节点的递归返回值即为整棵树是否为有效BST。

示例代码:

java 复制代码
class Solution {
    private long pre = Long.MIN_VALUE;

    public boolean isValidBST(TreeNode root) {
        if (root == null) {
            return true;
        }
        if (!isValidBST(root.left)) { // 左
            return false;
        }
        if (root.val <= pre) { // 中
            return false;
        }
        pre = root.val;
        return isValidBST(root.right); // 右
    }
}
相关推荐
㓗冽2 小时前
2026.03.27(第三天)
数据结构·c++·算法
sali-tec2 小时前
C# 基于OpenCv的视觉工作流-章44-直线卡尺
图像处理·人工智能·opencv·算法·计算机视觉
Magic--2 小时前
经典概率题:飞机座位分配问题(LeetCode 1227)超详细解析
算法·leetcode·职场和发展
urkay-2 小时前
Android 图片轮廓提取与重叠轮廓合并处理
android·算法·iphone
七七肆十九2 小时前
PTA 7-38 数列求和-加强版
数据结构·算法
SWAGGY..2 小时前
【C++初阶】:(5)内存管理
java·c++·算法
Zarek枫煜2 小时前
zig与C3的算法 -- 桶排序
c语言·嵌入式硬件·算法
Rooting++3 小时前
C语言中的共用体应用场景
算法
We་ct3 小时前
LeetCode 4. 寻找两个正序数组的中位数:二分优化思路详解
前端·数据结构·算法·leetcode·typescript·二分