建立四叉树[中等]

一、题目

给你一个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),即为二维前缀和需要使用的空间。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HarmonyOS4.0系列——05、状态管理之@Prop、@Link、@Provide、@Consume,以及@Watch装饰器

状态管理 看下面这张图 Components部分的装饰器为组件级别的状态管理&#xff0c;Application部分为应用的状态管理。开发者可以通过StorageLink/LocalStorageLink 实现应用和组件状态的双向同步&#xff0c;通过StorageProp/LocalStorageProp 实现应用和组件状态的单向同步。…

uniapp滑动页面切换和下拉刷新,触底加载更多(swiper + scroll-view)

因为官方文档乱七八糟的&#xff0c;所以自己来总结下 需求&#xff1a; 常见的上方tag标签切换&#xff0c;下方是页面&#xff0c;上面点击切换&#xff0c;下面页面也切换&#xff0c;下方列表有下拉刷新&#xff0c;触底加载更多 因为这两个组件都是固定高度的&#xff0c;…

透析PHP缓存问题

缓存已经成了项目中是必不可少的一部分&#xff0c;它是提高性能最好的方式&#xff0c;例如减少网络I/O、减少磁盘I/O 等&#xff0c;使项目加载速度变的更快。 缓存可以是CPU缓存、内存缓存、硬盘缓存&#xff0c;不同的缓存查询速度也不一样&#xff08;CPU缓存 > 内存缓…

C/C++调用matlab

C/C调用matlab matlab虽然可以生成C/C的程序&#xff0c;但其能力很有限&#xff0c;很多操作无法生成C/C程序&#xff0c;比如函数求解、优化、拟合等。为了解决这个问题&#xff0c;可以采用matlab和C/C联合编程的方式进行。使用matlab将关键操作打包成dll环境&#xff0c;再…

蓝凌EIS智慧协同平台 ShowUserInfo.aspx 存在 SQL注入漏洞

产品简介 蓝凌EIS智慧协同平台是一款专为企业提供高效协同办公和团队合作的产品。该平台集成了各种协同工具和功能&#xff0c;旨在提升企业内部沟通、协作和信息共享的效率。 漏洞概述 由于蓝凌EIS智慧协同平台 ShowUserInfo.aspx接口处未对用户输入的SQL语句进行过滤或验证…

如何使用 Helm 在 K8s 上集成 Prometheus 和 Grafana|Part 2

在 Part 1 中&#xff0c;我们一起了解了什么是 Prometheus 和 Grafana&#xff0c;以及使用这些工具的前提条件和优势。在本部分&#xff0c;将继续带您学习如何安装 Helm 以及如何使用 Prometheus Helm Charts。 开始使用 Helm 和 Helm Chart ArtifactHub 为 Helm Chart 提供…

SCP命令实现Linux和Windows系统间文件互传,dos窗口上传文件到sftp服务器

SCP windows 上传文件到Linux 操作步骤&#xff1a; 在文件所在目录开启dos执行命令 scp 文件全路径 目标主机账户ip:路径回车输入目标主机账户密码即可 SCP 从Linux上下载文件 scp 账户ip:文件绝对路径 ./当前用户路径 Windows系统dos窗口上传文件到sftp服务

MySQL从0到1全教程【1】MySQL数据库的基本概念以及MySQL8.0版本的部署

1 MySQL数据库的相关概念 1.1 数据库中的专业术语 1.1.1 数据库 (DB) 数据库是指:保存有组织的数据的容器(通常是一个文数据库 (database)件或一组文件)。 1.1.2 数据库管理系统 (DBMS) 数据库管理系统(DBMS)又称为数据库软件(产品)&#xff0c;用于管理DB中的数据 注意:…

海康摄像头配置电子围栏

需求背景 当有人进入到规划的区域内就会自动报警&#xff0c;目前配置的是语音播报闪光灯闪烁。 操作教程 1、打开配置界面 登录萤石云平台-设备管理-设备配置-立即配置 2、报警语音配置 默认进入的是配置界面&#xff0c;不要在这里配置。 不要在【配置】-【事件】-【事…

CSS 弹幕按钮动画

<template><view class="content"><button class="btn-23"><text class="text">弹幕按钮</text><text class="marquee">弹幕按钮</text></button></view></template><…

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

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

分布式消息服务kafka

分布式消息队列DMS 什么是消息中间件&#xff1f; 消息中间件是分布式系统中重要的组件&#xff0c;本质就是一个具有接收消息、存储消息、分发消息的队列&#xff0c;应用程序通过读写队列消息来通信。 例如&#xff1a;在淘宝购物时&#xff0c;订单系统处理完订单后&#…