【动态规划】1130. 叶值的最小代价生成树

news2024/11/27 2:16:01

1130. 叶值的最小代价生成树

难度:中等
力扣地址:https://leetcode.cn/problems/minimum-cost-tree-from-leaf-values/description/

题目内容

给你一个正整数数组 arr,考虑所有满足以下条件的二叉树:

每个节点都有 0 个或是 2 个子节点。
数组 arr 中的值与树的中序遍历中每个叶节点的值一一对应。
每个非叶节点的值等于其左子树和右子树中叶节点的最大值的乘积。
在所有这样的二叉树中,返回每个非叶节点的值的最小可能总和。这个和的值是一个 32 位整数。

如果一个节点有 0 个子节点,那么该节点为叶节点。

示例 1:
在这里插入图片描述

输入:arr = [6,2,4]
输出:32
解释:有两种可能的树,第一种的非叶节点的总和为 36 ,第二种非叶节点的总和为 32 。

示例 2:
在这里插入图片描述

输入:arr = [4,11]
输出:44

提示:

  • 2 <= arr.length <= 40
  • 1 <= arr[i] <= 15
  • 答案保证是一个 32 位带符号整数,即小于 2 31 2^{31} 231

解题过程 1 —— 小白的思考流程

由于本人能力有限,木有做出来。此处主要参考了官方的解题过程,结合自己的理解记录一下。

题目看起来很复杂,实际上也不简单。这里我们首先使用比较直观的方法求解:列举所有可能,并起初结果,然后返回最小的。如例1所示,这里我们先把两种情况画出来,就知道哪个结果更小了。

即:输入 6 2 4 时,有可能的结果是 6 * 4 + 2 * 4 = 32;也有可能是 6 * 4 + 2 * 6 = 36。 这里我们定义一个函数,用来求解三个结点时的最优结果。

int calculate(int a, int b, int c) {
    // 如果 d1 较小,则选择让 a 与 b 结合,成为兄弟结点
    int d1 = (a * b) + max(a, b) * c;

    // 如果 d2 较小,则选择让 b 与 c 结合,
    int d2 = (b * c) + max(b, c) * a;
    return min(d1, d2);
}

接着我们需要思考的问题是,如果超过3个结点,该如何应对 ?

比如现在的输入是 [6,4,5,1],最终的结果是 55,计算方法是

在这里插入图片描述

这种情况下,我们发现 51 是兄弟结点,然后 5与1 的结合结果与 4 是兄弟结点,而 6 与它们仨的结合体是兄弟节点。

这里我们应当把其他情况也列一下:

在这里插入图片描述
在这里插入图片描述
这个时候我们可以发现,这些结果也就是 calculate(a, b, c) 得到结果 d1 然后再 将 d1d 重新计算;或者计算 calculate(b, c, d) 得到 d2,然后再计算 d2a 的结果。

结论1:总而言之,我们需要划分,也就是分治过程

接下来我们可以开始处理更加复杂的情况了,如果总共有 5 个结点,我们可以先将前3个看为一个整理,然后与第4个与第5个计算得到结果;也可以 ……

这里我们直接强行计算所有情况。

接下来需要考虑,左右子树的划分过程,前面给出的例子中,[6, 4, 2, 1] 可以分为三种情况,1 + 3(左子树1个,右子树3个),2 + 2 (左右子树各一个)以及 3 + 1 (左子树3个,右子树1个)。

类似地,如果更多结点,我们需要考虑这种左右子树的划分过程,并且根据每种情况计算结果。

结论2:需要考虑所有的左右子树划分情况(循环遍历所有可能)。

开始写代码:

class Solution {
public:
    int mctFromLeafValues(vector<int>& arr) {
        int n = arr.size();
        // dp[i][j] 表示从 arr[i] 到 arr[j] 构成的子树的非叶节点值的最小总和
        vector<vector<int>> dp(n, vector<int>(n, INT_MAX / 4));
        // maxVal[i][j] 表示从 arr[i] 到 arr[j] 之间的最大值
        vector<vector<int>> maxVal(n, vector<int>(n));
        for (int j = 0; j < n; j++) {
            // 计算 arr[i] 到 arr[j] 之间的最大值。
            // maxVal[i][j - 1] 是子数组 arr[i] 到 arr[j-1] 的最大值。
            // 新加入的元素是 arr[j],所以 maxVal[i][j] 是 maxVal[i][j - 1] 和 arr[j] 中的较大值。
            // 当只有一个元素时,最大值就是元素本身
            maxVal[j][j] = arr[j];
             // 单个节点没有非叶节点,值为 0
            dp[j][j] = 0;
            for (int i = j - 1; i >= 0; i--) {
                // 更新 maxVal[i][j] 为子数组 arr[i] 到 arr[j] 的最大值
                maxVal[i][j] = max(arr[i], maxVal[i + 1][j]);
                // 枚举分割点 k,将子数组分为 arr[i] 到 arr[k] 和 arr[k + 1] 到 arr[j]
                for (int k = i; k < j; k++) {
                    // 更新 dp[i][j] 为分割后子树的最小非叶节点值总和
                    dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j] + maxVal[i][k] * maxVal[k + 1][j]);
                }
            }
        }
        return dp[0][n - 1];
    }
};

时间复杂度: O ( n 3 ) O(n^3) O(n3)
空间复杂度: O ( n 2 ) O(n^2) O(n2)

方法总结

  • 动态规划的核心 在于通过解决子问题来解决更大规模的问题。我们通过定义 dp[i][j] 来表示子数组 arr[i]arr[j] 的最小非叶节点值的总和,这样我们可以逐步从小规模问题解决到大规模问题。

  • 分治法的核心思想 是将一个大问题分解成若干个小问题分别解决,然后将小问题的解组合成大问题的解。在这个问题中,我们通过枚举分割点 k 来将子数组 arr[i]arr[j] 分成两部分,即 arr[i]arr[k]arr[k+1]arr[j],然后分别解决这两部分子问题,最后将它们的解组合起来。

具体来说,分治思想体现在:

  1. 分解:将子数组 arr[i]arr[j] 分成两部分,即 arr[i]arr[k]arr[k+1]arr[j]
  2. 解决:分别解决这两个子问题,即计算 dp[i][k]dp[k+1][j]
  3. 合并:将两个子问题的解 dp[i][k]dp[k+1][j] 合并,同时加上当前划分下的非叶节点值 maxVal[i][k] * maxVal[k+1][j]

Smileyan
2024.06.23 00:27

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1851965.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

算法04 模拟算法之一维数组相关内容详解【C++实现】

大家好&#xff0c;我是bigbigli&#xff0c;模拟算法我们将分为几个章节来讲&#xff0c;今天我们只看一维数组相关的题目 目录 模拟的概念 训练&#xff1a;开关灯 解析 参考代码 训练&#xff1a;数组变化 解析 参考代码 训练&#xff1a;折叠游戏 解析 参考代码 …

韩顺平0基础学java——第29天

p592-599 线程 用户线程和守护线程 1.用户线程:也叫工作线程&#xff0c;当线程的任务执行完或通知方式结束 2守护线程:一般是为工作线程服务的&#xff0c;当所有的用户线选束&#xff0c;守护线程自动结束 3.常见的守护线程:垃圾回收机制 当我们希望当main线程结束后&…

C# Onnx Yolov5 水果识别,人员识别,物品识别 人工智能

目录 先上效果 来电废话&#xff0c;但实用 网络成功案例实践易失败的原因 万物检测涉及技术 下载合集 关键代码 全部代码 实操vs2022安装关键 YOLO V5核心库编译 编写自己识别软件 更新相关依赖 标注字库文件 测试效果 名词解释YOLO 名词解释ONNX 源码 直播教…

利用第三方服务对目标进行被动信息收集防止被发现(web安全白帽子)

利用第三方服务对目标进行被动信息收集防止被发现&#xff08;web安全白帽子&#xff09; 1 被动信息收集1.1 信息收集内容1.2 信息用途 2 信息收集-DNS2.1 DNS信息收集NSLOOKUP2.1.1 ping2.1.2 nslookup 2.2 DNS信息收集-DIG&#xff08;此命令查到的结果更复杂些&#xff0c;…

Apache IoTDB vs InfluxDB 开源版,架构性能全面对比!

分布式、端边云同步、读写查询性能&#xff0c;Apache IoTDB 与 InfluxDB 开源版的详尽对照&#xff01; 在物联网&#xff08;IoT&#xff09;领域&#xff0c;数据的采集、存储和分析是确保系统高效运行和决策准确的重要环节。随着物联网设备数量的增加和数据量的爆炸式增长&…

Golang | Leetcode Golang题解之第174题地下城游戏

题目&#xff1a; 题解&#xff1a; func calculateMinimumHP(dungeon [][]int) int {n, m : len(dungeon), len(dungeon[0])dp : make([][]int, n 1)for i : 0; i < len(dp); i {dp[i] make([]int, m 1)for j : 0; j < len(dp[i]); j {dp[i][j] math.MaxInt32}}dp[…

爬虫笔记11——网页爬取数据写入csv

数据持久化存储进文件&#xff0c;前面的文章已经讲解如何存储入Excel表格了&#xff0c;有兴趣可以看一下&#xff0c;现在来记录一下如何存储进csv文件。 csv存储 csv简述 csv就是一个普通文件&#xff0c;里面的内容是每一行中的数据用逗号分隔&#xff0c;然后文件后缀为…

Golang | Leetcode Golang题解之第179题最大数

题目&#xff1a; 题解&#xff1a; func largestNumber(nums []int) string {sort.Slice(nums, func(i, j int) bool {x, y : nums[i], nums[j]sx, sy : 10, 10for sx < x {sx * 10}for sy < y {sy * 10}return sy*xy > sx*yx})if nums[0] 0 {return "0"…

教师信息管理系统

摘要 随着互联网技术与信息时代的高速发展和应用&#xff0c;教育行业也逐渐意识到互联网技术与信息化管理的融合。在传统的教师信息管理中&#xff0c;往往需要大量的纸质档案和手工处理&#xff0c;不仅效率低下&#xff0c;而且容易出现信息丢失和错误。因此为了提高教师信…

解决vs2022无法安装扩展程序包

在工具—>NuGet包管理器—>程序包管理设置&#xff0c;把程序包源设置为https://www.nuget.org/api/v2/&#xff0c;如下图 然后就可以在管理解决方案包界面搜索下载自己需要的扩展包

安全之战,巅峰对决 | 第八届XCTF国际网络攻防联赛总决赛首日赛况公布!

XCTF联赛由清华大学蓝莲花(Blue-Lotus)战队发起&#xff0c;国家创新与发展战略研究会主办&#xff0c;赛宁网安总体承办&#xff0c;旨在探索网络安全创新能力与发展潜力。第八届XCTF国际网络攻防联赛总决赛在四川省经济和信息化厅、四川省教育厅、四川省公安厅的指导下&#…

kafka(二)安装部署(2)windows

一、前提 安装Kafka之前&#xff0c;需要安装JDK、Zookeeper、Scala, 本次安装版本选择&#xff1a; JDK&#xff1a;1.8 Zookeeper&#xff1a;3.6.4 Scala&#xff1a;2.12 Kafka&#xff1a;3.5.2 1、jdk Java Downloads | Oracle 见jdk下载安装。 2、Zookeeper 下载…

Android进程间通信 Messenger详解

//这里服务端Service是运行在单独的进程中的 android:process“:other” class MessengerService : Service() { private lateinit var mMessenger: Messenger override fun onBind(intent: Intent): IBinder { log(TAG, “onBind~”) //传入Handler实例化Messenger mMes…

Android测量

最大模式&#xff08;MeasureSpec.AT_MOST&#xff09; 这个也就是父组件&#xff0c;能够给出的最大的空间&#xff0c;当前组件的长或宽最大只能为这么大&#xff0c;当然也可以比这个小。 最高两位是11的时候表示”最大模式”。即MeasureSpec.AT_MOST未指定模式&#xff08;…

Java | Leetcode Java题解之第179题最大数

题目&#xff1a; 题解&#xff1a; class Solution {public String largestNumber(int[] nums) {int n nums.length;// 转换成包装类型&#xff0c;以便传入 Comparator 对象&#xff08;此处为 lambda 表达式&#xff09;Integer[] numsArr new Integer[n];for (int i 0;…

windows git配置多个账号

window下git多账号配置_百度搜索 (baidu.com) 最重要的是这里生成新的id_rsa文件的时候&#xff0c;bash窗口是在 .ssh路径下 其实就是这个窗口在什么路径下执行的就是生成在什么路径 下面窗口路径不对&#xff0c;不是Desktop&#xff0c;应该是.ssh 如果是Desktop或者任何一…

如何解决跨区域文件传输存在的安全管控问题?

⼤型企业和集团为扩⼤市场份额、优化资源配置&#xff0c;会在不同地区设⽴多级下属分⽀机构、研发中心、实验室等&#xff0c;存在研发数据横向或纵向流转的需求&#xff0c;研发数据进行跨区域文件传输的场景。跨区域可能是网络区域&#xff0c;也可能是地理区域&#xff0c;…

常见数字化转型方案撰写的思维模式

通过这一段时间的学习和倾听,结合DAMA数据管理知识体系学习与项目实践,对大部分数据治理类项目、信息化建设和数字化转型项目的思维模式做了一些总结梳理,具体有如下四种,供参考。 一、方法1:结合环境六边形法 1.要点题,弄清楚问题是什么 2.目标原则有哪些,补充哪些 3.…

Android O 适配详细指南

NotificationChannel channel new NotificationChannel(mChannelId, name, NotificationManager.IMPORTANCE_DEFAULT); mNotificationManager.createNotificationChannel(channel); } } // 创建通知传入channelId NotificationCompat.Builder builder new NotificationCompat…

【Linux详解】缓冲区优化 | 进度条的实现 | Linux下git 的上传

目录 一. 缓冲区 1. 缓冲区概念 2. 缓冲区作用 2.1 提升读写效率 2.2 减少等待时间 3. 缓冲区刷新策略 3.4 特殊策略 4. 缓冲区存储位置 5. 总结 二. 实现进度条 引入&#xff1a;倒计时 process.c 三. Linux下git的上传 sum 一. 缓冲区 1. 缓冲区概念 缓冲区是…