題目描述:給定一個 n×n 的二進制矩陣(值只有 0 或 1),建構對應的四元樹(Quad Tree)。若一個區域內所有值相同,則該區域為葉節點(isLeaf = true,val 為該值);否則將區域分割為四個等大的象限,遞迴建構四個子節點。
解題思路:本題是分治法的直接應用。對每個矩形區域,先判斷它是否為「均勻區域」(所有元素相同):
如何高效判斷區域均勻性:最直接的方式是線性掃描整個區域,時間 O(n²)。更高效的方式是使用二維前綴和(2D Prefix Sum)預處理,使每次查詢任意矩形的元素總和降為 O(1),從而在 O(1) 時間判斷是否均勻(總和為 0 或 width×height 時均勻)。
時間複雜度:O(n²) — 二維前綴和預處理需 O(n²);遞迴建構過程中,每個葉節點代表一塊均勻區域,所有葉節點覆蓋整個 n×n 網格,故總工作量為 O(n²)。若不使用前綴和而是每次線性掃描,最壞複雜度退化至 O(n² log n)。
空間複雜度:O(n²) — 前綴和陣列佔 O(n²) 空間;遞迴堆疊深度為 O(log n);四元樹節點數最壞為 O(n²)(每個葉對應 1×1 格子時)。
1. Build 2D prefix sum array from grid (size (n+1) x (n+1)) 2. Define querySum(prefix, r1, c1, size): - Return sum of grid values in square region starting at (r1,c1) with given size 3. Define build(prefix, row, col, size): a. total = querySum(prefix, row, col, size) b. If total == 0: return leaf node with val=false c. If total == size*size: return leaf node with val=true d. half = size / 2 e. Create internal node f. node.topLeft = build(prefix, row, col, half) g. node.topRight = build(prefix, row, col+half, half) h. node.bottomLeft = build(prefix, row+half, col, half) i. node.bottomRight = build(prefix, row+half, col+half, half) j. Return node 4. Return build(prefix, 0, 0, n)
方法一:樸素遞迴(線性掃描判斷均勻性) 不預處理前綴和,每次對當前區域線性掃描所有元素來判斷是否均勻。時間複雜度 O(n² log n)(每層遞迴掃描 n² 個元素,共 log n 層)。實作簡單,但比前綴和方案慢,適合 n 較小的情境。
方法二:記憶化遞迴(Memoization) 若同一區域可能被多次查詢(在更複雜的變體問題中),可將每個 (row, col, size) 三元組的結果快取起來,避免重複計算。對本題標準版本,由於每個區域只計算一次,記憶化帶來的收益有限,但在動態更新場景(如 LeetCode 699 Falling Squares)中非常有用。