We want to use quad trees to store an N x N
boolean grid. Each cell in the grid can only be true or false. The root node represents the whole grid. For each node, it will be subdivided into four children nodes until the values in the region it represents are all the same.html
Each node has another two boolean attributes : isLeaf
and val
. isLeaf
is true if and only if the node is a leaf node. The val
attribute for a leaf node contains the value of the region it represents.node
Your task is to use a quad tree to represent a given grid. The following example may help you understand the problem better:數組
Given the 8 x 8
grid below, we want to construct the corresponding quad tree:less
It can be divided according to the definition above:ide
The corresponding quad tree should be as following, where each node is represented as a (isLeaf, val)
pair.函數
For the non-leaf nodes, val
can be arbitrary, so it is represented as *
.ui
Note:spa
N
is less than 1000
and guaranteened to be a power of 2.
這道題讓咱們根據一個二維數組來創建一棵四叉樹,關於四叉樹的介紹題目中也了給了wiki百科的連接。可是博主開始看到題目中給的那個例子,沒怎麼看懂。後來分析大神們的代碼,才略微弄明白了一些。原來葉結點表示的是值相同的一片區域,好比咱們看二維數組圖示那行的第三個圖,首先整個數組被分紅了四等份,左上,左下,和右下部份內的值均相同,那麼他們都是一個葉結點,而右上只有再四等分一下,才能使各自部份內的值相同,因此其就不是葉結點,而四等分後的每一個區間纔是葉結點。題目中限定了N的值必定是2的指數,就是說其若是可分的話,必定能夠四等分,而以前說了,只有區間內的值不一樣時,才須要四等分,不然總體就看成一個葉結點。因此咱們須要check四等分區間內的值是否相同,固然,咱們能夠將二維數組拆分爲四個二維數組,可是那樣可能不過高效,並且還佔用額外空間,一個比較好的選擇是用座標變量來控制等分數組的範圍,咱們只須要一個起始點座標,和區間的長度,就能夠精肯定位一個區間了。好比說對於例子中的整個二維數組數組來講,知道起始點座標 (0, 0),還有長度8,就知道表示的是哪一個區間。咱們能夠遍歷這個區間上的其餘全部的點,跟起點對比,只要有任何點跟起點不相同,則說明該區間是可分的,由於咱們前面說了,只有一個區間上全部的值均相同,才能看成一個葉結點。只要有不一樣,就表示能夠四分,那麼咱們就新建一個結點,這裏的左上,左下,右上,和右下四個子結點就須要用過調用遞歸函數來實現了,實現原理都同樣,重要的地方就是肯定每一個四分區間的起點和長度,長度好肯定,都是當前長度的一半,而後就是把各個區間的起點肯定好,這個也不難,就是細心一點,不要寫錯了就能夠了,另外,對於非葉結點,結點值能夠是true或者false都沒問題。若是某個區間上全部值均相同,那麼就生成一個葉結點,結點值就跟區間值相同,isLeaf是true,四個子結點均爲NULL便可,參見代碼以下:code
解法一:htm
class Solution { public: Node* construct(vector<vector<int>>& grid) { return build(grid, 0, 0, grid.size()); } Node* build(vector<vector<int>>& grid, int x, int y, int len) { if (len <= 0) return NULL; for (int i = x; i < x + len; ++i) { for (int j = y; j < y + len; ++j) { if (grid[i][j] != grid[x][y]) { return new Node(true, false, build(grid, x, y, len / 2), build(grid, x, y + len / 2, len / 2), build(grid, x + len/ 2, y, len / 2), build(grid, x + len / 2, y + len / 2, len / 2)); } } } return new Node(grid[x][y] == 1, true, NULL, NULL, NULL, NULL); } };
還有一種寫法,記錄了區間的左上點和右下點,知道這兩個點也能夠肯定一個區間的位置,總體思路和上面的方法並無什麼太大的區別,參見代碼以下:
解法二:
class Solution { public: Node* construct(vector<vector<int>>& grid) { return build(grid, 0, 0, grid.size() - 1, grid.size() - 1); } Node* build(vector<vector<int>>& grid, int r1, int c1, int r2, int c2) { if (r1 > r2 || c1 > c2) return NULL; bool isLeaf = true; int val = grid[r1][c1], rowMid = (r1 + r2) / 2, colMid = (c1 + c2) / 2; for (int i = r1; i <= r2; ++i) { for (int j = c1; j <= c2; ++j) { if (grid[i][j] != val) { isLeaf = false; break; } } } if (isLeaf) return new Node(val == 1, true, NULL, NULL, NULL, NULL); return new Node(false, false, build(grid, r1, c1, rowMid, colMid), build(grid, r1, colMid + 1, rowMid, c2), build(grid, rowMid + 1, c1, r2, colMid), build(grid, rowMid + 1, colMid + 1, r2, c2)); } };
參考資料:
https://leetcode.com/problems/construct-quad-tree/
https://leetcode.com/problems/construct-quad-tree/discuss/151j684/Recursive-Java-Solution
https://leetcode.com/problems/construct-quad-tree/discuss/154420/My-Java-Recursive-Solution