【C++单调栈 记忆化搜索】1130. 叶值的最小代价生成树|1919

本文涉及的基础知识点

C++单调栈
C++记忆化搜索
C++动态规划

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

给你一个正整数数组 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 位带符号整数,即小于 231

记忆化搜索

n = arr.length
数组 arr 中的值与树的中序遍历中每个叶节点的值一一对应。    ⟺    \iff 将arr分成左右两部分,arr1,arr2,arr1对应左子树,arr2对应右子树。
如果arr只有一个元素,其最小和为arr[0]。
否则拆分arr1,arr2,递归处理。两这皆不能为空。

动态规划的状态记录

dp[i][j] 记录arr[i…j]对应的子树最小和。空间复杂度:O(nn)

动态规划的状态方程

dp[i][j] = min ⁡ k = i j − 1 \min_{k=i}^{j-1} mink=ij1(dp[i][k]+dp[k+1][j]) + arr[i…j]之积。arr[i…j]之积 可以预处理,也可以用前缀和。由于答案在int32范围内,故arr之积也在int32范围内。
单个状态的时间复杂度:O(n)
时间复杂度:O(nnn) 注意:dp[i][j]的状态记录下来,初始-1,如果是-1则计算,否则查询。

初始调用

Cal(0,arr.lenght-1)

代码

核心代码

class Solution {
    
    
		public:
			int mctFromLeafValues(vector<int>& arr) {
    
    
				m_arr = arr;
				m_dp.assign(arr.size(), vector<int>(arr.size(),-1));
				m_max.assign(arr.size(), vector<int>(arr.size(), 0));
				for (int i = 0; i < arr.size(); i++) {
    
    
					m_max[i][i] = arr[i];
					for (int j = i + 1; j < arr.size(); j++) {
    
    
						m_max[i][j] = max(arr[j], m_max[i][j - 1]);
					}
				}
				return Cal(0, arr.size() - 1);
			}
			int Cal(int left, int r) {
    
    
				if (-1 != m_dp[left][r]) {
    
     return m_dp[left][r]; }
				if (left == r) {
    
    
					return m_dp[left][r] = 0;
				}
				int iMin = INT_MAX;				
				for (int i = left; i < r; i++) {
    
    
					iMin = min(iMin, Cal(left, i) + Cal(i + 1, r)+ m_max[left][i]* m_max[i+1][r]);
				}
				return m_dp[left][r] = iMin ;
			}
			vector<vector<int>> m_dp,m_max;
			vector<int> m_arr;
	
		};

单元测试

vector<int> arr;
		TEST_METHOD(TestMethod11)
		{
    
    
			arr = {
    
     6,2,4 };
			auto res = Solution().mctFromLeafValues(arr);
			AssertEx(32, res);
		}
		TEST_METHOD(TestMethod12)
		{
    
    
			arr = {
    
     4,11 };
			auto res = Solution().mctFromLeafValues(arr);
			AssertEx(44, res);
		}

单调栈

本题就是临项消除:消除成本是两项的乘积,合并后的项是两者的较大者。
证明难度太大,建议暂且放一放。孤立的知识点,难学易忘,效率低得发指。

扩展阅读

我想对大家说的话
工作中遇到的问题,可以按类别查阅鄙人的算法文章,请点击《算法与数据汇总》。
学习算法:按章节学习《喜缺全书算法册》,大量的题目和测试用例,打包下载。重视操作
有效学习:明确的目标 及时的反馈 拉伸区(难度合适) 专注
闻缺陷则喜(喜缺)是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛
失败+反思=成功 成功+反思=成功

视频课程

先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771
如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。

猜你喜欢

转载自blog.csdn.net/he_zhidan/article/details/142434301