leetcode 刷题:叶值的最小生成树

问题描述

 
给你一个正整数数组 arr,考虑所有满足以下条件的二叉树:
   (1)每个节点都有 0 个或是 2 个子节点。
   (2)数组 arr 中的值与树的中序遍历中每个叶节点的值一一对应。(知识回顾:如果一个节点有 0 个子节点,那么该节点为叶节点。)
   (3)每个非叶节点的值等于其左子树和右子树中叶节点的最大值的乘积。
   在所有这样的二叉树中,返回每个非叶节点的值的最小可能总和。这个和的值是一个 32 位整数。(具体题目可到leetcode题库中寻找)
 
提示:
2 <= arr.length <= 40
1 <= arr[i] <= 15
答案保证是一个 32 位带符号整数,即小于 2^31。
 

解决思路:单调递减栈

为什么可以用单调递减栈?

   对于满足中序遍历的数组,数组中的数在二叉树的叶子节点中一定是从左到右排列的。考虑从底层到顶层依次生成叶子节点和非叶子节点,值越小的数应该在越底层,因为底层的叶子节点如果比较大,参与乘法的次数多,整体的非叶节点之和越大。所以越小的叶子节点应该在二叉树越底层。到这,我们可以考虑维护一个单调递减栈,将数组中的数依次入栈,若数组当前数比栈顶数小,则入栈。若数组当前数比栈顶数大,则将当前栈顶值出栈,当前非叶节点和等于出栈的栈顶值与数组当前值以及当前栈顶值中较小的那个数的乘积。这里代表出栈的数与数组当前值以及当前栈顶值中较小的那个数搭配成为一个树的两个叶子节点。当数组遍历完后,再将单调栈中存入的数组数依次出栈,当前非叶节点值等于出栈值和当前栈顶值之积。将所有非叶节点值相加即得到最小的非叶节点总和。
 

单调递减栈C++代码实现

class Solution {
public:
    int mctFromLeafValues(vector<int>& arr) {
    //定义一个单调递减栈
    vector <int> stack;
    //根据题目取值范围,向栈中插入一个较大的数,例如30,保证栈不为空。
    stack.push_back(30);
    int len=arr.size();
    int result=0;
    //将数组arr中的数按照单调递减栈规则入栈,非叶节点和等于当前arr值和栈顶值之间较小值之积的和
    for(int i=0;i<len;i++){
        while(arr[i]>=stack.back()&&stack.back()!=30){
              int temp=stack.back();
              stack.pop_back();
              result+=temp*min(arr[i],stack.back());
     }
         stack.push_back(arr[i]);
                          }
     //将栈内存有的arr数组的数,依次相乘出栈                     
     while(stack.size()>2){
         int temp=stack.back();
         stack.pop_back();
         result+=temp*stack.back();
                          }

    return result;
    }
};

 

总结

   这题其实一开始,我的想法是用dp(动态规划)来做,但是在考虑的过程中发现,它其实是一个数组选取下一个更小元素的问题,因为对于该题的二叉树,底层的节点一定是比较小的节点,那么我们在遍历数组时就可以利用单调递减栈的性质,将较小的节点挑选出来作为底层节点去生成二叉树。
   今天其实是被某个粉丝催更的一天,让我在时隔三个月后再次回归csdn博客的写作,感谢这位粉丝。之后还是想说不能偷懒,csdn的博客以后还是一周一更。我还是想把每一次的学习和成长记录下来,这样方便忘了的时候复习,同时也可以作为技术成长的一种见证。
   本篇文章的代码还有可以优化的部分,如果文章中有错误或不妥之处,可以在评论下留言,本人看到后会及时订正。溜了,溜了~

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值