【每日一题Day309】LC823带因子的二叉树 | dp

带因子的二叉树【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)

你可能感兴趣的:(每日一题,动态规划,leetcode)