带因子的二叉树【LC823】
给出一个含有不重复整数元素的数组
arr,每个整数arr[i]均大于 1。用这些整数来构建二叉树,每个整数可以使用任意次数。其中:每个非叶结点的值应等于它的两个子结点的值的乘积。
满足条件的二叉树一共有多少个?答案可能很大,返回 对
109 + 7取余 的结果。
-
思路
-
**寻找子问题:**假设 a a a和 b b b为 x x x的因子,并都存在在数组
arr中,根据乘法原理,以 x x x为根节点的合法子树的个数,为以 a a a为根节点的合法子树的个数和以 b b b为根节点的合法子树的个数的乘积。该问题是一个重复子问题,因此可以使用dp解决 -
状态定义: d p [ i ] dp[i] dp[i]为以 a r r [ i ] arr[i] arr[i]为根节点的合法子树的个数
-
状态转移:
-
首先由于一个数的因子一定小于自身,因此需要从小到大处理每个数,故而对
arr进行升序排序 -
为了快速判断某个数是否在
arr中及其下标,因此使用哈希表记录每个元素的值及其下标 -
枚举每个数 a r r [ i ] arr[i] arr[i],在 j ∈ [ 0 , i ) j \in [0,i) j∈[0,i)范围内,找到其所有的因子对【顺序不同为不同的树】
满足 a r r [ i ] % a r r [ j ] = = 0 arr[i] \% arr[j] == 0 arr[i]%arr[j]==0,并且 a r r [ i ] / a r r [ j ] arr[i]/arr[j] arr[i]/arr[j]在数组中
d p [ i ] = d p [ i ] + d p [ j ] ∗ d p [ i n d e x . g e t ( a r r [ i ] / a r r [ j ] ) ] dp[i]=dp[i]+dp[j]*dp[index.get(arr[i]/arr[j])] dp[i]=dp[i]+dp[j]∗dp[index.get(arr[i]/arr[j])]
-
-
**状态初始化:**每棵树只存在根节点,因此 d p [ i ] dp[i] dp[i]初始化为1
-
-
实现
class Solution { public static final int MOD = (int)(1e9 + 7); public int numFactoredBinaryTrees(int[] arr) { Arrays.sort(arr); long res = 0L; int n = arr.length; long[] dp = new long[n]; Map<Integer,Integer> index = new HashMap<>(); for (int i = 0; i < n; i++){ index.put(arr[i], i); } Arrays.fill(dp, 1L); for (int i = 0; i < n; i++){ for (int j = 0; j < i; j++){ if (arr[i] % arr[j] == 0 && index.containsKey(arr[i] / arr[j])){ dp[i] += dp[j] * dp[index.get(arr[i] / arr[j])] ; } } res += dp[i]; } return (int)(res % MOD) ; } }-
复杂度
- 时间复杂度: O ( n 2 ) O(n^2) O(n2)
- 空间复杂度: O ( n ) O(n) O(n)
-

文章描述了一种算法,通过动态规划解决带因子的二叉树构造问题,给定一个不重复整数数组,计算满足特定条件的二叉树数量,结果对10^9+7取余。算法涉及数组排序、因子查找和状态转移。
2334

被折叠的 条评论
为什么被折叠?



