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

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于Java的学生成绩管理系统

你好呀&#xff0c;我是计算机学姐码农小野&#xff01;如果有相关需求&#xff0c;可以私信联系我。 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;Java技术&#xff0c;B/S结构 工具&#xff1a;MyEclipse&#xff0c;MySQL 系统展示 首页 个人中…

软件测试——稳定性测试:adb Monkey

Monkey 1. Monkey1.1 Monkey 是什么1.2 Monkey 测试场景1.3 Monkey 特点1.4 Monkey 在哪里1.5 测试准备事项1.6 Monkey 参数列表 2. 基本命令3. 常用参数4. 事件类型5. 调试参数6. 日志管理7. 日志错误定位8. Monkey测试可以发现的问题 1. Monkey 1.1 Monkey 是什么 Monkey是一…

计算机网络期末

1、IP 地址为:192.168.0.254,它的子网掩码应该为( ) A.255.255.255.0 B.255.255.254.0 C.255.255.252.0 D.255.255.0.0 2、最容易产生网络可靠性瓶颈问题的拓扑构型是&#xff08; &#xff09;。 A 总线型 B 星型 C 环型 D 网状型 3、HTTP 就是电子邮件阅读协议&#xff0…

使用Vue+Antv-X6实现一个输送线可视化编辑器(支持拖拽、自定义连线、自定义节点等)

最近公司有这样的业务&#xff0c;要实现一个类似流程图的编辑器&#xff0c;可以拖拉拽之类的&#xff0c;网上寻找了一番&#xff0c;最终决定使用Antv-X6这个图形引擎&#xff0c;非常强大&#xff0c;文档多看几遍也就能上手使用了。感觉还不错就写个使用心得期望能帮助到同…

访问网站时IP被屏蔽是什么原因?

在互联网使用中&#xff0c;有时我们可能会遇到访问某个网站时IP地址被屏蔽的情况。IP地址被网站屏蔽是一个相对常见的现象&#xff0c;而导致这种情况的原因多种多样&#xff0c;包括恶意行为、违规访问等。本文将解释IP地址被网站屏蔽的常见原因&#xff0c;同时&#xff0c;…

如何理解广角镜头和长焦镜头的区别。

为什么广角镜头的视野会比长焦镜头的视野大呢&#xff1f; 我之前用等光程解释了景深&#xff0c;也解释了为什么焦距越远&#xff0c;成像越大&#xff0c;但是从来没有提到过视野范围这个概念。实际上在我之前建立的数学模型中&#xff0c;物曲面S是无限大的&#xff0c;像曲…

Python,PyCharm,Anaconda安装及使用教程

一、Python下载及安装 Python官网Welcome to Python.org 当前最新版是3.11.0版本&#xff1a;python-3.11.0-amd64.exe 下一步&#xff0c;下一步进行安装即可 选择&#xff1a;“Customize installation”,出现下图&#xff1a; 点击“Next”下一步&#xff0c;出现如下图…

HTTP网络协议

1.HTTP &#xff08;1&#xff09;概念&#xff1a; Hyper Text Transfer Protocol&#xff0c;超文本传输协议规定了浏览器和服务器之间数据传输的规则。 &#xff08;2&#xff09;特点 基于TCP协议:面向连接&#xff0c;安全基于请求-响应模型的:一次请求对应一次响应HTTP协…

Redis源码学习:quicklist的设计与实现

为什么需要quicklist 假设你已经知道了ziplist的缺陷&#xff1a; 虽然节省空间&#xff0c;但是申请内存必须是连续的&#xff0c;如果内存占用比较多&#xff0c;申请效率低要存储大量数据&#xff0c;超过了ziplist的最佳上限后&#xff0c;性能有影响 借鉴分片思想&…

说说 SSL 的错误认识和不足之处

最近明月在学习折腾 LNMP 期间无意中建了一个 Typecho 的博客小站&#xff0c;近一周的折腾下来&#xff0c;收获真的不少&#xff0c;致使兴趣也越来越浓了&#xff0c;在升级 LNMP 的时候捎带手的给这个 Typecho 博客也启用了 SSL。并且开启了 memcached 和 OPcache 优化加速…

Spring Cache常见问题解决

目录 一 报错:Null key returned for cache operation 二 报错&#xff1a;类型转换异常 三 取出的数据为null 一 报错:Null key returned for cache operation 这里报错有两种情况&#xff1a; 第一&#xff0c;如果你在新增的方法上使用Cacheable注解&#xff0c;那么肯定是…

终极解决方案,传统极速方案,下载软件的双雄对决!

在数字资源日益丰富的今天&#xff0c;下载管理器成为了我们日常生活中不可或缺的工具。市场上两款备受欢迎的下载管理软件——Internet Download Manager&#xff08;IDM&#xff09;和迅雷11&#xff0c;它们以各自的特色和优势&#xff0c;满足了不同用户群体的需求。 软件…

5.3 Python len()函数:获取字符串长度或字节数

Python len()函数详解&#xff1a;获取字符串长度或字节数 Python 中&#xff0c;要想知道一个字符串有多少个字符&#xff08;获得字符串长度&#xff09;&#xff0c;或者一个字符串占用多少个字节&#xff0c;可以使用 len 函数。 len 函数的基本语法格式为&#xff1a; …

python-今年第几天

[题目描述] 定义一个结构体变量&#xff08;包括年、月、日&#xff09;。 计算该日在本年中是第几天&#xff0c;注意闰年问题。输入格式&#xff1a; 年 月 日。输出格式&#xff1a; 当年第几天。样例输入 2000 12 31样例输出 366 数据范围 对于100%的数据&#xff0c;保…

解决MNIST数据集下载慢,或者Http连接失败问题

下载MNIST数据集时遇到速度慢的问题 解决&#xff1a;手动从MNIST数据集的官方网站直接使用下载好的数据文件&#xff0c;放到指定目录下&#xff0c;再进行调取即可。 手动下载地址&#xff1a;MNIST官网 http://yann.lecun.com/exdb/mnist/ 【仍需要连接外网】 这里我提供…

ATA-4052C高压功率放大器在新能源汽车安全测试中的应用

新能源汽车的崛起已经改变了汽车行业的格局&#xff0c;为环境友好型交通方式提供了更多的选择。为了确保这些新型汽车的安全性和可靠性&#xff0c;进行全面的安全测试是至关重要的。高压功率放大器在新能源汽车的安全测试中发挥着重要的作用&#xff0c;本文将介绍其应用以及…

已解决:Vector析构异常Opencv Assert _CrtIsValidHeapPointer

已解决&#xff1a;Vector析构异常Opencv Assert _CrtIsValidHeapPointer 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页&#xff0c;我是博主英杰&#xff0c;211科班出身&#xff0c;就职于医疗科技公司&#xff0c;热衷分享知识&#xff0c;武汉…

PathDecider 详细解读

目录 PathDecider的主要功能 PathDecider代码分析 Process() MakeObjectDecision() MakeStaticObstacleDecision() MakeStaticObstacleDecision()的流程图​编辑 MakeStaticObstacleDecision()的代码解析 GenerateObjectStopDecision() PathDecider里用到的其他函数 …

C语言入门4-函数和程序结构

函数举例 读取字符串&#xff0c;如果字符串中含有ould则输出该字符串&#xff0c;否则不输出。 #include <stdio.h>// 函数声明 int getLine(char s[], int lim); int strindex(char s[], char t[]);int main() {char t[] "ould"; // 要查找的目标子字符串…

自然语言处理学习路线(1)——NLP的基本流程

NLP基本流程 【NLP基本流程】 0. 获取语料 ——> 1. 语料预处理 ——> 2. 特征工程&选择 ——> 3. 模型训练 ——> 4. 模型输出&上线 【NLP基本流程图】 Reference 1. 自然语言处理(NLP)的一般处理流程&#xff01;-腾讯云开发者社区-腾讯云 2. …