题目描述
给出一个含有不重复整数元素的数组,每个整数均大于 1。
我们用这些整数来构建二叉树,每个整数可以使用任意次数。
其中:每个非叶结点的值应等于它的两个子结点的值的乘积。
满足条件的二叉树一共有多少个?返回的结果应 模 10 ^ 9 + 7。
样例
输入: A = [2, 4]
输出: 3
解释: 我们可以得到这些二叉树: [2], [4], [4, 2, 2]。
输入: A = [2, 4, 5, 10]
输出: 7
解释: 我们可以得到这些二叉树: [2], [4], [5], [10], [4, 2, 2], [10, 2, 5], [10, 5, 2]。
提示
1 <= A.length <= 1000.
2 <= A[i] <= 10 ^ 9.
算法
(动态规划) O(n2)
- 将数组从小到大排序。这里的二叉树要求满二叉树(每个结点要求有两个儿子结点)。
- 设 f(i) 表示以 A[i] 为根,满足条件的二叉树一共有多少个。
- 对于每一个 i,设置 f(i)=1,表示单根的二叉树,然后枚举 j<i 满足 A[i],并且 A[i]/A[j] 在数组里出现过,则 f(i)=f(i)+f(j)∗f(loc(A[i]/A[j])),loc(x) 表示查询 x 的下标。这个公式的意思是,将 A[j] 和 A[i]/A[j] 这两个数字分别作为左右子树。
- 最终答案为 ∑n−1i=0f(i)。
时间复杂度
- 排序需要 O(nlogn) 的时间。
- 动态规划的状态数为 O(n),每次寻找转移需要 O(n) 的时间,故时间复杂度为 O(n2)。
空间复杂度
- 需要额外的数组和哈希表,空间复杂度为 O(n)。
C++ 代码
class Solution {
public:
int numFactoredBinaryTrees(vector<int>& A) {
const int mod = 1000000007;
int n = A.size();
sort(A.begin(), A.end());
unordered_map<int, int> hash;
for (int i = 0; i < n; i++)
hash[A[i]] = i;
vector<int> f(n);
int ans = 0;
for (int i = 0; i < n; i++) {
f[i] = 1;
for (int j = 0; j < i; j++)
if (A[i] % A[j] == 0 && hash.find(A[i] / A[j]) != hash.end()) {
int k = hash[A[i] / A[j]];
f[i] = (f[i] + (long long)(f[j]) * f[k]) % mod;
}
ans = (ans + f[i]) % mod;
}
return ans;
}
};