558. 四叉樹交集
四叉樹是一種樹數據,其中每個結點恰好有四個子結點:
topLeft
、topRight
、bottomLeft
和bottomRight
。四叉樹通常被用來劃分一個二維空間,遞歸地將其細分爲四個象限或區域。我們希望在四叉樹中存儲 True/False 信息。四叉樹用來表示
N * N
的布爾網格。對於每個結點, 它將被等分成四個孩子結點直到這個區域內的值都是相同的。每個節點都有另外兩個布爾屬性:isLeaf
和val
。當這個節點是一個葉子結點時isLeaf
爲真。val
變量儲存葉子結點所代表的區域的值。例如,下面是兩個四叉樹 A 和 B:
A: +-------+-------+ T: true | | | F: false | T | T | | | | +-------+-------+ | | | | F | F | | | | +-------+-------+ topLeft: T topRight: T bottomLeft: F bottomRight: F B: +-------+---+---+ | | F | F | | T +---+---+ | | T | T | +-------+---+---+ | | | | T | F | | | | +-------+-------+ topLeft: T topRight: topLeft: F topRight: F bottomLeft: T bottomRight: T bottomLeft: T bottomRight: F
你的任務是實現一個函數,該函數根據兩個四叉樹返回表示這兩個四叉樹的邏輯或(或並)的四叉樹。
A: B: C (A or B): +-------+-------+ +-------+---+---+ +-------+-------+ | | | | | F | F | | | | | T | T | | T +---+---+ | T | T | | | | | | T | T | | | | +-------+-------+ +-------+---+---+ +-------+-------+ | | | | | | | | | | F | F | | T | F | | T | F | | | | | | | | | | +-------+-------+ +-------+-------+ +-------+-------+
提示:
A
和B
都表示大小爲N * N
的網格。N
將確保是 2 的整次冪。- 如果你想了解更多關於四叉樹的知識,你可以參考這個 wiki 頁面。
- 邏輯或的定義如下:如果
A 爲 True
,或者B 爲 True
,或者A 和 B 都爲 True
,則 "A 或 B" 爲 True。
解法一
/*
// Definition for a QuadTree node.
class Node {
public:
bool val;
bool isLeaf;
Node* topLeft;
Node* topRight;
Node* bottomLeft;
Node* bottomRight;
Node() {}
Node(bool _val, bool _isLeaf, Node* _topLeft, Node* _topRight, Node* _bottomLeft, Node* _bottomRight) {
val = _val;
isLeaf = _isLeaf;
topLeft = _topLeft;
topRight = _topRight;
bottomLeft = _bottomLeft;
bottomRight = _bottomRight;
}
};
*/
class Solution {
public:
Node* build(Node* root1, Node* root2) {
if(root1->isLeaf || root2->isLeaf) {//遇到葉結點
if(!(root1->isLeaf)) {//交換
Node* temp = root1;
root1 = root2;
root2 = temp;
}
if(root1->val) return root1;
else return root2;
}
Node* newTree = new Node(false, false, nullptr, nullptr, nullptr, nullptr);//構造(非葉子)結點
newTree->topLeft = build(root1->topLeft, root2->topLeft);
newTree->topRight = build(root1->topRight, root2->topRight);
newTree->bottomLeft = build(root1->bottomLeft, root2->bottomLeft);
newTree->bottomRight = build(root1->bottomRight, root2->bottomRight);
if(newTree->topLeft->isLeaf && newTree->topRight->isLeaf &&
newTree->bottomLeft->isLeaf && newTree->bottomRight->isLeaf &&
newTree->topLeft->val == newTree->topRight->val &&
newTree->topRight->val == newTree->bottomLeft->val &&
newTree->bottomLeft->val == newTree->bottomRight->val)//合併
newTree = newTree->topLeft;
return newTree;
}
Node* intersect(Node* quadTree1, Node* quadTree2) {
if(!quadTree1) return quadTree2;
if(!quadTree2) return quadTree1;
return build(quadTree1, quadTree2);
}
};
思路:
- 同時對兩個四叉樹進行遞歸遍歷,終止條件爲至少其中一個結點爲葉子結點。
- 如果遇到葉結點,就求並集返回。上述解中使用了交換結點指針來避免多次判斷。
- 額外要注意的是,如果一個結點的4個子結點都是葉子,而且值相同,那需要把它們合併成一個葉子結點。
爲了編程簡潔,這裏留了一個潛在的問題。構造並集樹的過程中,返回的子結點並不都是新創建的(通過new操作),有些直接將原樹的結構指針直接返回,所以求完並集操作後原來的兩個四叉樹可能失效,而且更容易造成內存泄漏。如果是在實際應用中,最好是複製而不是直接引用。