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