建立四叉树[中等]

一、题目

给你一个n * n矩阵grid,矩阵由若干01组成。请你用四叉树表示该矩阵grid。你需要返回能表示矩阵grid四叉树的根结点。四叉树数据结构中,每个内部节点只有四个子节点。此外,每个节点都有两个属性:
【1】val:储存叶子结点所代表的区域的值。1对应True0对应False。注意,当isLeafFalse时,你可以把True或者False赋值给节点,两种值都会被判题机制接受。
【2】isLeaf: 当这个节点是一个叶子结点时为True,如果它有4个子节点则为False

class Node {
    public boolean val;
    public boolean isLeaf;
    public Node topLeft;
    public Node topRight;
    public Node bottomLeft;
    public Node bottomRight;
}

我们可以按以下步骤为二维区域构建四叉树:
【1】如果当前网格的值相同(即,全为0或者全为1),将isLeaf设为True,将val设为网格相应的值,并将四个子节点都设为Null然后停止。
【2】如果当前网格的值不同,将isLeaf设为False,将val设为任意值,然后如下图所示,将当前网格划分为四个子网格。
【3】使用适当的子网格递归每个子节点。

四叉树格式: 你不需要阅读本节来解决这个问题。只有当你想了解输出格式时才会这样做。输出为使用层序遍历后四叉树的序列化形式,其中null表示路径终止符,其下面不存在节点。它与二叉树的序列化非常相似。唯一的区别是节点以列表形式表示[isLeaf, val]。如果isLeaf或者val的值为True,则表示它在列表[isLeaf, val]中的值为1;如果isLeaf或者val的值为False,则表示值为0

示例 1:

输入:grid = [[0,1],[1,0]]
输出:[[0,1],[1,0],[1,1],[1,1],[1,0]]
解释:此示例的解释如下:请注意,在下面四叉树的图示中,0表示false1表示True

示例 2:

输入:grid = [[1,1,1,1,0,0,0,0],[1,1,1,1,0,0,0,0],[1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1],[1,1,1,1,0,0,0,0],[1,1,1,1,0,0,0,0],[1,1,1,1,0,0,0,0],[1,1,1,1,0,0,0,0]]
输出:[[0,1],[1,1],[0,1],[1,1],[1,0],null,null,null,null,[1,0],[1,0],[1,1],[1,1]]
解释:网格中的所有值都不相同。我们将网格划分为四个子网格。topLeftbottomLeftbottomRight均具有相同的值。topRight具有不同的值,因此我们将其再分为4个子网格,这样每个子网格都具有相同的值。解释如下图所示:

n == grid.length == grid[i].length
n == 2x其中0 <= x <= 6

二、代码

【1】递归: 我们可以使用递归的方法构建出四叉树。具体地,我们用递归函数dfs(r0,c0,r1,c1)处理给定的矩阵gridr0行开始到r1−1行,从c0c1−1列的部分。我们首先判定这一部分是否均为01,如果是,那么这一部分对应的是一个叶节点,我们构造出对应的叶节点并结束递归;如果不是,那么这一部分对应的是一个非叶节点,我们需要将其分成四个部分:行的分界线为(r0+r1)/2​​,列的分界线为(c0+c1)/2​​,根据这两条分界线递归地调用dfs函数得到四个部分对应的树,再将它们对应地挂在非叶节点的四个子节点上。

class Solution {
    public Node construct(int[][] grid) {
        return dfs(grid, 0, 0, grid.length, grid.length);
    }

    public Node dfs(int[][] grid, int r0, int c0, int r1, int c1) {
        boolean same = true;
        for (int i = r0; i < r1; ++i) {
            for (int j = c0; j < c1; ++j) {
                if (grid[i][j] != grid[r0][c0]) {
                    same = false;
                    break;
                }
            }
            if (!same) {
                break;
            }
        }

        if (same) {
            return new Node(grid[r0][c0] == 1, true);
        }

        Node ret = new Node(
            true,
            false,
            dfs(grid, r0, c0, (r0 + r1) / 2, (c0 + c1) / 2),
            dfs(grid, r0, (c0 + c1) / 2, (r0 + r1) / 2, c1),
            dfs(grid, (r0 + r1) / 2, c0, r1, (c0 + c1) / 2),
            dfs(grid, (r0 + r1) / 2, (c0 + c1) / 2, r1, c1)
        );
        return ret;
    }
}

时间复杂度: O(n^2log⁡n)。这里给出一个较为宽松的时间复杂度上界。记T(n)为边长为n的数组需要的时间复杂度,那么「判定这一部分是否均为01」需要的时间为O(n^2),在这之后会递归调用4规模为n/2的子问题,那么有:T(n)=4T(n/2)+O(n^2)以及:T(1)=O(1)根据主定理,可以得到T(n)=O(n^2log⁡n)。但如果判定需要的时间达到了渐近紧界Θ(n^2),那么说明这一部分包含的元素大部分都是相同的,也就是说,有很大概率在深入递归时遇到元素完全相同的一部分,从而提前结束递归。因此O(n^2log⁡n)的时间复杂度是很宽松的,实际运行过程中可以跑出与方法二O(n^2)时间复杂度代码相似的速度。
空间复杂度: O(log⁡n),即为递归需要使用的栈空间。

【2】递归 + 二维前缀和优化: 我们可以对方法一中暴力判定某一部分是否均为01的代码进行优化。具体地,当某一部分均为0时,它的和为0;某一部分均为1时,它的和为这一部分的面积大小。我们可以与处理出数组grid的二维前缀和,这样一来,当我们需要判定某一部分是否均为01时,可以在O(1)的时间内得到这一部分的和,从而快速地进行判断。

class Solution {
    public Node construct(int[][] grid) {
        int n = grid.length;
        int[][] pre = new int[n + 1][n + 1];
        for (int i = 1; i <= n; ++i) {
            for (int j = 1; j <= n; ++j) {
                pre[i][j] = pre[i - 1][j] + pre[i][j - 1] - pre[i - 1][j - 1] + grid[i - 1][j - 1];
            }
        }
        return dfs(grid, pre, 0, 0, n, n);
    }

    public Node dfs(int[][] grid, int[][] pre, int r0, int c0, int r1, int c1) {
        int total = getSum(pre, r0, c0, r1, c1);
        if (total == 0) {
            return new Node(false, true);
        } else if (total == (r1 - r0) * (c1 - c0)) {
            return new Node(true, true);
        }

        Node ret = new Node(
            true,
            false,
            dfs(grid, pre, r0, c0, (r0 + r1) / 2, (c0 + c1) / 2),
            dfs(grid, pre, r0, (c0 + c1) / 2, (r0 + r1) / 2, c1),
            dfs(grid, pre, (r0 + r1) / 2, c0, r1, (c0 + c1) / 2),
            dfs(grid, pre, (r0 + r1) / 2, (c0 + c1) / 2, r1, c1)
        );
        return ret;
    }

    public int getSum(int[][] pre, int r0, int c0, int r1, int c1) {
        return pre[r1][c1] - pre[r1][c0] - pre[r0][c1] + pre[r0][c0];
    }
}

时间复杂度: O(n^2)。在最坏情况下,数组grid中交替出现01,此时每一个叶节点对应着1×1的区域。记T(n)为边长为n的数组需要的时间复杂度,那么有:T(n)=4T(n/2)+O(1)以及:T(1)=O(1)根据主定理,可以得到T(n)=O(n^2)。预处理二维前缀和需要的时间也为O(n^2),因此总时间复杂度为O(n^2)
空间复杂度: O(n^2),即为二维前缀和需要使用的空间。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/309343.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

使用SpringCache操作Redis缓存数据

SpringCache概念 SpringCache是一个框架&#xff0c;实现了基于注解的缓存功能&#xff0c;只需要简单的加一个注解&#xff0c;就能实现缓存功能。 SpringCache提供了一层抽象&#xff0c;底层可以切换不同的缓存实现&#xff0c;例如&#xff1a; EHCacheCaffeineRedis 使…

怎么在unity3D工程中导入Newtonsoft.Json

打开 Unity 编辑器。 转到菜单栏的 “Window”&#xff08;窗口&#xff09;选项&#xff0c;然后选择 “Package Manager”&#xff08;包管理器&#xff09; 在搜索框中输入 “Newtonsoft Json” 进行搜索。 注意&#xff1a;要选择Unity Registry 在搜索结果中&#xf…

强化学习求解TSP(五):Qlearning求解旅行商问题TSP(提供Python代码)

一、Qlearning简介 Q-learning是一种强化学习算法&#xff0c;用于解决基于奖励的决策问题。它是一种无模型的学习方法&#xff0c;通过与环境的交互来学习最优策略。Q-learning的核心思想是通过学习一个Q值函数来指导决策&#xff0c;该函数表示在给定状态下采取某个动作所获…

Windows下安装mariadb10.5数据库及配置详细教程

1、简介 MariaDB数据库管理系统是一款MySQL的替代数据库。MariaDB由MySQL的创始人麦克尔维德纽斯主导开发&#xff0c;是可扩展的&#xff0c;可靠的SQL服务器的合乎逻辑的选择&#xff0c;MariaDB 10.5 是 MariaDB 当前的稳定系列。 2、下载 下载地址&#xff1a;Download M…

【FPGA/verilog -入门学习17】vivado 实现串口自发自收程序

1&#xff0c;需求 PC使用串口助手给FPGA板发送9600 波特率的数据&#xff0c;FPGA板接收到数据后&#xff0c;回复同样的数据给PC 2&#xff0c;需求分析 按模块可以划分为&#xff1a; rx接收模块&#xff0c;将输入的8位并行rx 数据转换成[7:0]rx_data 信号&#xff0c;当…

圣诞老人遇见 GenAI:利用大语言模型、LangChain 和 Elasticsearch 破译手写的圣诞信件

在北极的中心地带&#xff0c;圣诞老人的精灵团队面临着巨大的后勤挑战&#xff1a;如何处理来自世界各地儿童的数百万封信件。 圣诞老人表情坚定&#xff0c;他决定是时候将人工智能纳入圣诞节行动了。 圣诞老人坐在配备了最新人工智能技术的电脑前&#xff0c;开始在 Jupyter…

【Linux】Ubuntu 解压 zip、z01、z02等压缩文件的方法,Linux如何解压分卷压缩的

zip分卷压缩&#xff0c;在windows上压缩来的&#xff0c;如何解压这种文件&#xff1a; -rw-rw-r-- 1 20401094656 Dec 10 20:06 FFHQ.z01 -rw-rw-r-- 1 20401094656 Dec 10 20:10 FFHQ.z02 -rw-rw-r-- 1 20401094656 Dec 10 23:22 FFHQ.z03 -rw-rw-r-- 1 20401094656 Dec 10…

docker微服务案例

文章目录 建立简单的springboot项目(boot3)boot2建立通过dockerfile发布微服务部署到docker容器编写Dockerfile打包成镜像运行镜像微服务 建立简单的springboot项目(boot3) 1.建立module 2. 改pom <?xml version"1.0" encoding"UTF-8"?> <…

通过反射修改MultipartFile类文件名

1、背景 项目上有这样一个需求&#xff0c;前端传文件过来&#xff0c;后端接收后按照特定格式对文件进行重命名。(修改文件名需求其实也可以在前端处理的) //接口类似于下面这个样子 PosMapping("/uploadFile") public R uploadFile(List<MultipartFile> fil…

鸿蒙HarmonyOS学习手册_入门篇

鸿蒙HarmonyOS学习手册_入门篇 文章目录 鸿蒙HarmonyOS学习手册_入门篇入门快速入门开发准备基本概念UI框架应用模型工具准备 构建第一个ArkTS应用&#xff08;Stage模型&#xff09;-快速入门-入门创建ArkTS工程ArkTS工程目录结构&#xff08;Stage模型&#xff09;构建第一个…

day14 二叉树的遍历 递归遍历 迭代遍历 统一遍历

题目1&#xff1a;递归遍历 题目链接1&#xff1a;144 二叉树的前序遍历 题意 根据二叉树的根节点root&#xff0c;返回它的前序遍历 递归法 前序遍历&#xff1a;中左右 递归三部曲 1) 确定递归函数的参数和返回值 2&#xff09;确定终止条件 3&#xff09;确定单层递…

linux搭建SRS服务器

linux搭建SRS服务器 文章目录 linux搭建SRS服务器SRS说明实验说明搭建步骤推流步骤查看web端服务器拉流步骤final SRS说明 SRS&#xff08;simple Rtmp Server&#xff09;,是一个简单高效的实时视频服务器&#xff0c;支持RTMP/WebRTC/HLS/HTTP-FLV/SRT, 是国人自己开发的一款…

计算机基础面试题 |22.精选计算机基础面试题

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

坑记(HttpInputMessage)

一、背景知识 public interface HttpInputMessage extends HttpMessage Represents an HTTP input message, consisting of headers and a readable body.Typically implemented by an HTTP request on the server-side, or a response on the client-side.Since: 3.0 Author:…

windows安装Elasticsearch后使用ik分词器报错解决办法

最近在学习Elasticsearch&#xff0c;安装完成后下载了ik分词器压缩到plugins目录下启动es报错如下&#xff1a; java.security.AccessControlException: access denied (“java.io.FilePermission” “D:…\plugins\ik-analyzer\config\IKAnalyzer.cfg.xml” “read”)咋一看…

03 - 系统调用

---- 整理自 王利涛老师 课程 实验环境&#xff1a;宅学部落 www.zhaixue.cc 文章目录 1. 系统调用基本概念1.1 一个系统调用的例子1.2 什么是系统调用&#xff1f;软件复用的角度 2. 软中断&#xff1a;系统调用的入口2.1 权限管理2.2 系统调用号2.4 man 2 syscall2.5 实验&am…

全自动网页生成系统网站源码重构版

源码优点: 所有模板经过精心审核与修改&#xff0c;完美兼容小屏手机大屏手机&#xff0c;以及各种平板端、电脑端和360浏览器、谷歌浏览器、火狐浏览器等等各大浏览器显示。 免费制作 为用户使用方便考虑&#xff0c;全自动网页制作系统无需繁琐的注册与登入&#xff0c;直…

MongoDB 设置账号密码_mongodb设置用户名和密码

MongoDB 设置账号密码_mongodb设置用户名和密码 1、安装 安装可以看我这篇文章:https://blog.csdn.net/u014641168/article/details/123937775 2、说明 由于默认安装的MongoDB是没有设置用户密码的,极其危险,所以需要设置一下用户密码 3、创建用户 用Navicat15连接Mon…

Web组件的使用

文章目录 1 概述2 加载网页加载在线网页加载本地网页 3 网页缩放文本缩放 4 Web组件事件Web组件处理JS confirm事件 5 Web和JavaScript交互启用JavaScriptWeb组件调用JS方法JS调用Web组件方法 6 处理页面导航7 调试网络应用8 参考链接 1 概述 相信大家都遇到过这样的场景&…

Serverless 开拓无服务器时代:云计算的新趋势(下)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…