开启我的LeetCode刷题日记:427. 建立四叉树

45 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第8天,点击查看活动详情

编程世界总是离不了算法

最近在看框架源码时,会有很多算法的实现逻辑,有时候会感到吃力

于是决定蹭着假期,加强算法和数据结构相关的知识

那怎么提升呢?

其实我知道算法这东西没有捷径,多写多练才能提升,于是我开启我的LeetCode刷题之旅

第一阶段目标是:200道,每天12

为了不乱,本系列文章目录分为三部分:

  1. 今日题目:xxx
  2. 我的思路
  3. 代码实现

今日题目:417. 太平洋大西洋水流问题

给你一个 n * n 矩阵 grid ,矩阵由若干 0 和 1 组成。请你用四叉树表示该矩阵 grid 。

你需要返回能表示矩阵的 四叉树 的根结点。

注意,当 isLeaf 为 False 时,你可以把 True 或者 False 赋值给节点,两种值都会被判题机制 接受 。

四叉树数据结构中,每个内部节点只有四个子节点。此外,每个节点都有两个属性:

val:储存叶子结点所代表的区域的值。1 对应 True,0 对应 False; isLeaf: 当这个节点是一个叶子结点时为 True,如果它有 4 个子节点则为 False 。 class Node { public boolean val;     public boolean isLeaf;     public Node topLeft;     public Node topRight;     public Node bottomLeft;     public Node bottomRight; } 我们可以按以下步骤为二维区域构建四叉树:

如果当前网格的值相同(即,全为 0 或者全为 1),将 isLeaf 设为 True ,将 val 设为网格相应的值,并将四个子节点都设为 Null 然后停止。 如果当前网格的值不同,将 isLeaf 设为 False, 将 val 设为任意值,然后如下图所示,将当前网格划分为四个子网格。 使用适当的子网格递归每个子节点。

如果你想了解更多关于四叉树的内容,可以参考 wiki 。

四叉树格式:

输出为使用层序遍历后四叉树的序列化形式,其中 null 表示路径终止符,其下面不存在节点。

它与二叉树的序列化非常相似。唯一的区别是节点以列表形式表示 [isLeaf, val] 。

如果 isLeaf 或者 val 的值为 True ,则表示它在列表 [isLeaf, val] 中的值为 1 ;如果 isLeaf 或者 val 的值为 False ,则表示值为 0 。

我的思路

题目意思是要把 n * nn∗n 矩阵分割成 44 等份(左上、右上、左下、右下);分割之后返回一个 Node,Node 初始化要确定 33 个值:val、isLeaf、children(44 个子节点);如果 Node 不是叶子节点就接着递归分割它的 44 个子节点对应的子矩阵。

children:可以先递归求出 44 个子节点,当前节点是否有子节点由 isLeaf 决定 val:所有子节点的 val 之和除以 44 并向上取整(也可以向下取整) isLeaf:所有子节点的 val 之和是 44 或 00,且所有子节点都是叶子节点

矩阵大小是n * n(n = 2 ^ x, 0 <= x <= 6)n∗n(n=2 x ,0<=x<=6),矩阵最小是 111∗1 最大是 646464∗64,因此除最小矩阵外所有矩阵都可以被 44 等分,没有其他特殊情况需要处理

代码实现

var construct = function (grid) {
    const n = grid.length;

    function dfs(i0, i1, j0, j1) {
        if (i0 === i1 && j0 === j1) return new Node(grid[i0][j0], true);

        // 递归求出4个子节点
        const mi = Math.floor(i1 / 2 + i0 / 2), mj = Math.floor(j1 / 2 + j0 / 2);
        const tl = dfs(i0, mi, j0, mj);
        const tr = dfs(i0, mi, mj + 1, j1);
        const bl = dfs(mi + 1, i1, j0, mj);
        const br = dfs(mi + 1, i1, mj + 1, j1);

        const children = [tl, tr, bl, br];
        // 求出所有子节点的 val 之和
        const val = children.reduce((a, c) => a + c.val, 0);
        // isLeaf:所有子节点的 val 之和是 4 或 0,且所有子节点都是叶子节点 
        const isLeaf = (val % 4 === 0) && children.every((n) => n.isLeaf);

        // node.val:所有子节点的 val 之和除以 4 并向上取整
        // node.isLeaf:所有子节点的 val 之和是 4 或 0,且所有子节点都是叶子节点
        // 4个子节点:当前节点是否有子节点由 isLeaf 决定
        return new Node(Math.ceil(val / 4), isLeaf, ...(isLeaf ? [] : children));
    }

    return dfs(0, n - 1, 0, n - 1);
};

总结

实现方式其实有很多,这里仅供参考~

由于刚开始刷题,也不知道从哪里刷好,如果前辈们有好的建议,希望不吝赐教,感谢🌹