目录
一、题目
1、题目描述
给你一个正整数数组
arr
,考虑所有满足以下条件的二叉树:
- 每个节点都有
0
个或是2
个子节点。- 数组
arr
中的值与树的中序遍历中每个叶节点的值一一对应。- 每个非叶节点的值等于其左子树和右子树中叶节点的最大值的乘积。
在所有这样的二叉树中,返回每个非叶节点的值的最小可能总和。这个和的值是一个 32 位整数。
如果一个节点有 0 个子节点,那么该节点为叶节点。
2、接口
class Solution:
def mctFromLeafValues(self, arr: List[int]) -> int:
3、原题链接
1130. Minimum Cost Tree From Leaf Values
二、解题报告
1、思路分析
先考虑贪心做法:小值尽量在下层,大值尽量在上层,那么我们每次选当前剩余结点两两相邻最大值中最小的两个进行合并,合并n - 1次即可,这样做堆优化的话是O(nlogn)
我们发现,对于一段单调递减的序列,我们一定是从右往左依次合并最优
如果出现了“波谷”,比如a[0, i] 单调递减,此时遇到了a[i + 1] >= a[i],我们发现此时对于a[0, i] 就不一定是从右往左更优了,因为出现了a[i + 1],但是对于a[i]而言,其一定是和a[i - 1] 和 a[i + 1]中小的那个合并最优,对于a[i - 1]类似
所以我们可以维护一个单调递减栈,如果栈顶小于等于当前x,我们将栈顶出栈,和新栈顶和x中大的那个合并,如此操作以维护单调栈的单调性
每次维护单调栈事实上只是完成了a[0, i + 1]的部分元素的合并操作,并且这些操作是最优操作,并且不影响后续的合并操作,因为我们左边的贡献是按照左边最大值来的,合并小的值不会影响右边合并对结果的贡献
2、复杂度
时间复杂度: O(N)空间复杂度:O(N)
3、代码详解
class Solution:
def mctFromLeafValues(self, arr: list[int]) -> int:
res = 0
st = []
for x in arr:
while st and st[-1] <= x:
t = st.pop()
if not st or x < st[-1]:
res += x * t
else:
res += st[-1] * t
st.append(x)
while len(st) > 1:
t = st.pop()
res += t * st[-1]
return res