【力扣每日一题】2023.8.29 带因子的二叉树

文章讲述了如何使用动态规划方法解决一个问题,即给定一个整数数组,计算满足特定条件的二叉树数量,其中每个非叶子节点的值等于其左右子树节点值的乘积。通过排序数组、构建映射并遍历计算符合条件的组合,最后对结果取模10^9+7以避免数值溢出。
摘要由CSDN通过智能技术生成

目录

题目:

示例:

分析:

代码:


题目:

示例:

分析:

题目给我们一些元素,让我们用这些元素连接形成特定的二叉树,每种元素可以使用任意次数,形成的二叉树要求每个非叶子节点的值都为左右子树节点的值的乘积。

一个数要等于两个数的乘积,那么那两个数一定会比那一个数更小,所以我们可以从较小的数入手,那么我们首先将数组从小到大进行排序,接着从左到右,从小到大去遍历。

在遍历之前我们先做个预处理,我们用一个map来存住所有元素的值,以元素为键,值全部初始化为1。map每个键值对的含义就是以键为根节点能形参的二叉树有多少个,因为每个元素都可以以自身一个节点为一棵符合标准的二叉树,所以是初始化为1。

初始化完毕就开始遍历,我们需要套两层for循环,第一层去遍历每个根节点,去更新以当前节点为根节点所能形成的二叉树的数量,更新的方法就是第二层for循环去遍历比这个节点的值更小的元素,因为要相乘等于当前元素,那么乘数肯定是比当前元素更小的。

第一层遍历我们设下标为 i ,第二层下标为 j ,我们去寻找 arr[ i ] / arr[ j ] 这个元素在不在我们的map里,如果在,那么我们就把map里键为arr[ i ] 的键值对中的值加上以那两个乘数为根节点能形成的二叉树的数量的乘积,化简一下就是 m[ arr [ i ] ] += m[ arr[ i ] / arr[ j ] ] * m[ arr[ j ] ]。

由于我们是从小到大遍历的,所以我们每次都是会更新比后面的数更小的元素,以此元素为根节点能形参的二叉树,这样就可以得到推导出以后面较大的元素为根节点能形参的二叉树的数量。所以虽然我们没有用到dp数组,但它本质上来说还是属于动态规划。

还有一点要注意的就是题目有说要对结果取余10的九次方加7,所以为了避免数值溢出,我们每次操作都要做一个取余的操作。

代码:

class Solution {
public:
    int numFactoredBinaryTrees(vector<int>& arr) {
        int res=arr.size(); //单个节点可以单独为一棵树,初始化为数组长度
        sort(arr.begin(),arr.end());
        unordered_map<int,long>m;   //用来记录以每个数为根节点的二叉树数目
        for(int i:arr){
            m[i]=1;
        }
        for(int i=0;i<arr.size();i++){
            for(int j=0;j<i;j++){
                //如果发现arr[i]整除arr[j]的数也在数组里,那么可以多组成的二叉树数目等于以arr[j]为根节点的二叉树数目乘上以另一个除数为根节点的二叉树数目.
                if(arr[i]%arr[j]==0&&m.find(arr[i]/arr[j])!=m.end()){
                    int t=m[arr[i]/arr[j]]*m[arr[j]]%1000000007;
                    m[arr[i]]+=t;   //更新以arr[i]为根节点的二叉树数目.
                    res+=t;
                    res%=1000000007;
                }
            }
        }
        return res;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值