置頂

我的 VPython 教學文件 (HackMD 版本)

VPython 教學文件目錄 安裝及測試 基本語法 等速度直線運動 自由落下 終端速度 水平抛射 使用For迴圈計算水平抛射資料 斜向抛射 圓周運動 簡諧運動 單擺 木塊彈簧系統分離 重力及簡諧 行星運動 相疊木塊 雙重簡諧運動 一維彈性碰撞 ...

熱門文章

2026年10月22日 星期四

LeetCode 解題筆記:823. Binary Trees With Factors

作者:王一哲
日期:2026年10月22日


LeetCode 題目連結:823. Binary Trees With Factors

解題想法


中等難度題。題目給一個長度為 $n ~(1 \leq n \leq 1000)$ 、數字不重複的整數陣列 $arr ~(2 \leq arr[i] \leq 10^9)$,用這些整數組成二元樹,且除了葉節點之外,其它節點的值必須等於其子節點值的乘積,計算共有幾種排列方式。由於答案很大,將排列方式對 $10^9 + 7$ 取餘數。

這題考動態規畫。先將 $arr$ 由小到大排序,因為計算特定乘積的排列方式數量時,需要用到較小乘積的排列方式數量。接下來用字典 $dp$ 記錄乘積 $v$ 當作根節點有幾種二元樹排列方式,由於更新數值時需要將兩個因數對應的值相乘,可能會超出 int 的上限,用 long 儲存會比較安全。用一個 for 迴圈跑 $arr[0]$ ~ $arr[n-1]$,先設定 $dp[arr[i]] = 1$,代表只有根節點時方法數為 $1$;再用一個 for 迴圈跑 $arr[0]$ 到 $arr[i-1]$,如果 $arr[j]$ 是 $arr[i]$ 的因數,則 $dp[arr[i]]$ 的方法數要再加上兩個因數的方法數乘積,同時對 $10^9 + 7$ 取餘數。每次計算完 $dp[arr[i]]$ 時立刻更新答案 $ans$。這個寫法的效率不算很好,但是比較容易理解。

Python 程式碼


Runtime: 229 ms, beats 16.59%. Memory: 20.68 MB, beats 5.68%.
class Solution:
    def numFactoredBinaryTrees(self, arr: list[int]) -> int:
        mod = 10**9 + 7
        n = len(arr)  # 長度
        arr.sort()  # 由小到大排序
        ans = 0  # 答案
        dp = defaultdict(int)  # 數字 v 當作根節點有幾種二元樹組合

        for i in range(n):  # 跑 arr[0] ~ arr[n-1]
            dp[arr[i]] = 1  # 以 arr[i] 當作根節點且樹只有根節點,1 種組合
            for j in range(i):  # 找出 arr[i] 的因數
                if arr[i] % arr[j] == 0:  # arr[j] 是因數
                    dp[arr[i]] = (dp[arr[i]] + dp[arr[j]] * dp[arr[i] // arr[j]]) % mod  # 加上兩個因數組合數的乘積
            ans = (ans + dp[arr[i]]) % mod  # 更新答案
        return ans


C++ 程式碼


Runtime: 49 ms, beats 18.32%. Memory: 20.45 MB, beats 8.19%.
class Solution {
public:
    int numFactoredBinaryTrees(vector<int>& arr) {
        const int mod = 1000000007;
        int n = (int)arr.size(), ans = 0;  // 長度,答案
        sort(arr.begin(), arr.end());  // 由小到大排序
        unordered_map<int, long> dp;  // 數字 v 當作根節點有幾種二元樹組合

        for(int i = 0; i < n; i++) {  // 跑 arr[0] ~ arr[n-1]
            dp[arr[i]] = 1;  // 以 arr[i] 當作根節點且樹只有根節點,1 種組合
            for(int j = 0; j < i; j++) {  // 找出 arr[i] 的因數
                if (arr[i] % arr[j] == 0) {  // arr[j] 是因數
                    dp[arr[i]] = (dp[arr[i]] + dp[arr[j]] * dp[arr[i] / arr[j]] % mod) % mod;  // 加上兩個因數組合數的乘積
                }
            }
            ans = (ans + dp[arr[i]]) % mod;  // 更新答案
        }
        return ans;
    }
};


沒有留言:

張貼留言