目录
题目:
示例:
分析:
代码:
题目:
示例:
分析:
题目给我们一些元素,让我们用这些元素连接形成特定的二叉树,每种元素可以使用任意次数,形成的二叉树要求每个非叶子节点的值都为左右子树节点的值的乘积。
一个数要等于两个数的乘积,那么那两个数一定会比那一个数更小,所以我们可以从较小的数入手,那么我们首先将数组从小到大进行排序,接着从左到右,从小到大去遍历。
在遍历之前我们先做个预处理,我们用一个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;}
};