558. Quad Tree Intersection(四叉樹交集)

558. 四叉樹交集

四叉樹是一種樹數據,其中每個結點恰好有四個子結點:topLefttopRightbottomLeft 和 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   |
|       |       |  |       |       |  |       |       |
+-------+-------+  +-------+-------+  +-------+-------+

 

提示:

  1. A 和 B 都表示大小爲 N * N 的網格。
  2. N 將確保是 2 的整次冪。
  3. 如果你想了解更多關於四叉樹的知識,你可以參考這個 wiki 頁面。
  4. 邏輯或的定義如下:如果 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);
    }
};

思路:

  1. 同時對兩個四叉樹進行遞歸遍歷,終止條件爲至少其中一個結點爲葉子結點。
  2. 如果遇到葉結點,就求並集返回。上述解中使用了交換結點指針來避免多次判斷。
  3. 額外要注意的是,如果一個結點的4個子結點都是葉子,而且值相同,那需要把它們合併成一個葉子結點。

爲了編程簡潔,這裏留了一個潛在的問題。構造並集樹的過程中,返回的子結點並不都是新創建的(通過new操作),有些直接將原樹的結構指針直接返回,所以求完並集操作後原來的兩個四叉樹可能失效,而且更容易造成內存泄漏。如果是在實際應用中,最好是複製而不是直接引用。

2019/06/1 18:17
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章