[力扣每日习题][1339]. 分裂二叉树的最大乘积 2026.01.07

[力扣每日习题][1339]. 分裂二叉树的最大乘积 2026.01.07

难度评级:中等

题目:

给你一棵二叉树,它的根为 root 。请你删除 1 条边,使二叉树分裂成两棵子树,且它们子树和的乘积尽可能大。

由于答案可能会很大,请你将结果对 10^9 + 7 取模后再返回。

示例1:

输入:root = [1,2,3,4,5,6] 输出:110 解释:删除红色的边,得到 2 棵子树,和分别为 11 和 10 。它们的乘积是 110 (11*10)
示例2:

输入:root = [1,null,2,3,4,null,null,5,6] 输出:90 解释:移除红色的边,得到 2 棵子树,和分别是 15 和 6 。它们的乘积为 90 (15*6)

解题思路:DFS

        可以先计算得到所有节点的和,再通过数组存储所有子树的和,遍历数组的时候,计算:子树和  × (所有节点和 - 子树和),也就是分割成两个子树的乘积,找出最大的那一个乘积即可。

        深度优先搜索就是沿着一条路走到底,走不通了再回到上一层继续走。可以采用递归的方式实现,将根节点作为起始节点放入函数当中,函数需要完成如下操作:

        ① 定义 left 、 right、temp 3个参数,每次调用 DFS 函数的时候都需要重置为 0 ;

        ② 判断是否有左孩子,有就调用 DFS 函数,并且将函数的返回值存入 left 中,没有就下一步;

        ③ 判断是否有右孩子,有就调用 DFS 函数,并且将函数的返回值存入 right 中,没有就下一步;

        ④ 计算 temp = left + right + 当前节点的值;

        ⑤ 将 temp 存入子树和的数组中。

        ⑥ 返回 temp(当前子树的和);

        解析:根节点调用 DFS 函数的时候,会一直嵌套直到找到二叉树最左边的那个叶子节点,接下来,由于 left 和 right 为 0,那么 temp = 0 + 0 + 当前节点的值,将 temp 返回至上一层,也就是当前节点的父亲节点,父亲节点已经完成了 ② ,在这一层 left 的值是刚才计算得到的 temp,接下来进行 ③ ,如果没有右孩子那么 right = 0,在这一层的 temp = left + 0 + 当前节点的值,结束这层循环,再返回上一层。

        理解 DFS 的关键就是,先找到一条路一直到底,然后再慢慢往回退

        接下来我们用一颗二叉树来模拟一下这个 DFS 的流程。

        以如下二叉树为例,依次分析每个节点,下面是根节点的初始状态,将各个参数重置为 0,temp是当前节点孩子子树的和+当前节点值;注意这里的 left 和 right 分别指的左孩子子树的和、右孩子子树的和,不是左孩子和右孩子的值,在代码中为 left = DFS(2);right = DFS(3);是递归调用函数后返回的值。


        对于 1 这个节点,它有左孩子,那么这里需要递归调用 DFS 函数,将 2 这个节点作为根节点进行分析,对应着步骤 ②,2 这个节点进入后,它需要开始循环它的 DFS 函数。


        节点 2 有左孩子 4,那么将节点 4 作为根节点进行分析,调用 DFS 函数。


        此时节点 4 ,进行步骤 ②、③,由于它没有孩子,那么只能进行步骤 ④,计算 temp,最后将计算结果保存。


        第三层 4 进行步骤 ⑥,返回上一层,将计算结果返回给上一层对应调用 DFS(4)的那个参数,上一层调用 DFS(4)的是 第二层 2 在步骤 ② 的时候将左孩子进行递归调用 DFS,那么值就返回给第二层 2 的参数 left


        第二层 2 的步骤 ② 结束,现在进行步骤 ③ ,它有右孩子,那么将节点 5 调用 DFS 函数,作为根节点进行分析。


        节点 5,没有左右孩子,直接进行步骤 ④。


        进行步骤 ⑥,将值返回给上一层的 right。


        现在第三层 5 结束,第二层 2 进行步骤 ④,计算它自己的 temp。


        第二层 2 ,进行步骤 ⑥,将值返回给上一层的 left。


        第二层 2 结束,现在对一层 1 进行步骤 ③,它有右孩子,将右孩子递归调用 DFS


        节点 3 ,它没有左孩子,只有右孩子,那么它直接进行步骤 ③。


        第三层 6 ,没有孩子,是叶子节点,直接步骤 ④,计算 temp。


        进行步骤 ⑥,返回上一层,将值给上一层的 right。


        第二层 3 进行步骤 ④。


        进行步骤 ⑥,返回上一层,将值返回给上一层的 right。


        第一层 1 进行步骤 ④。


        最后进行步骤 ⑥,将最后的值返回即可,在递归调用的时候,所有的子树和都已计算并保存至一个数组,接下来只需要遍历数组,计算 每棵子树和  * (总和 - 该子树和) 找到最大值就可以了。


题解代码如下:

/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode() : val(0), left(nullptr), right(nullptr) {} * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} * }; */ class Solution { public: const int MOD = 1e9 + 7; long long dfs(TreeNode* root, vector<long long>& list){ long long l = 0; long long r = 0; long long temp = 0; if (root -> left != nullptr){ l = dfs(root -> left, list); } if (root -> right != nullptr){ r = dfs(root -> right, list); } temp = l + r + root -> val; list.push_back(temp); return temp; } int maxProduct(TreeNode* root) { vector <long long> list; // 用于存储所有子树和 long long sum = dfs(root, list); long long res = 0; for (auto i:list){ long long cal = i * (sum - i); if (cal > res){ res = cal; } } return res % MOD; } };

优化思路:暂无。

Read more

【c++】c++的四种类型转换(static_cast,reinterpret_cast,const_cast,dynamic_cast)

【c++】c++的四种类型转换(static_cast,reinterpret_cast,const_cast,dynamic_cast)

小编个人主页详情<—请点击 小编个人gitee代码仓库<—请点击 c++系列专栏<—请点击 倘若命中无此运,孤身亦可登昆仑,送给屏幕面前的读者朋友们和小编自己! 目录 * 前言 * 一、c语言中的类型转换 * 隐式类型转换 * 强制类型转换 * const常变量的强制类型转换 * 总结 * 二、c++的四种类型转换 * static_cast * reinterpret_cast * const_cast * dynamic_cast * 三、RTTI * 总结 前言 【c++】特殊类的设计(不能拷贝的类,只能在堆/栈上创建对象的类,不能被继承的类,单例模式——饿汉模式、懒汉模式)——书接上文 详情请点击<—— 本文由小编为大家介绍——【c+

By Ne0inhk
C++ 模板编程基础:泛型编程入门与实践

C++ 模板编程基础:泛型编程入门与实践

第33篇:C++ 模板编程基础:泛型编程入门与实践 一、学习目标与重点 * 掌握模板的核心概念、分类(函数模板、类模板)及基本语法 * 理解泛型编程的思想,能够独立编写函数模板和类模板 * 掌握模板的实例化、特化、偏特化等关键技术 * 解决模板使用中的常见问题(类型推导失败、编译错误等) * 结合实际场景运用模板提升代码复用性和灵活性 * 了解模板与STL的关联,为后续STL学习奠定基础 💡 核心重点:模板的语法规则、类型参数与非类型参数的使用、模板特化的应用场景、泛型编程的核心价值 二、模板与泛型编程概述 2.1 什么是泛型编程 泛型编程(Generic Programming)是一种代码复用技术,核心思想是“编写与类型无关的通用代码,在使用时再指定具体类型”,实现“一次编写,多次复用”。 🗄️ 生活中的泛型类比: * 快递盒:同一个快递盒(通用容器)可装手机、书籍、衣物(不同类型数据)

By Ne0inhk
【C++】类和对象(中)

【C++】类和对象(中)

一、类的默认成员函数 编译器会自动生成的成员函数称为默认成员函数。一个类,不写的情况下编译器会默认生成以下6个默认成员函数。另外在C++11中,增加了两个默认成员函数,移动构造和移动赋值。默认成员函数从两方面学习: 1. 我们不写时,编译器默认生成的函数行为是啥?满足我们的需求吗? 编译器默认生成的函数不满足我们的需求,那如何自己实现? 二、构造函数 构造函数主要任务是对象实例化时初始化对象。就像每次写栈或队列时需要初始化Stack Init()、Queue Init(),用了构造函数就不需要写这一步。 构造函数的特点:函数名与类名相同:类class Stack,类中的函数Stack()无返回值。也无void对象实例化时系统会自动调用对应的构造函数构造函数可以重载如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦用户显式定义编译器将不再生成无参构造函数、全缺省构造函数、我们不写构造时编译器默认生成的构造函数,都叫做默认构造函数。但是这三个函数有且只有一个存在,不能同时存在。无参构造函数和全缺省构造函数虽然构成函数重载,但是调用时会存在歧

By Ne0inhk