【六十四】【算法分析与设计】699. 掉落的方块,离散化操作,线段树优化,区间查询sum+区间更新update

699. 掉落的方块

在二维平面上的 x 轴上,放置着一些方块。

给你一个二维整数数组 positions ,其中 positions[i] = [left(i), sideLength(i)] 表示:第 i 个方块边长为 sideLength(i) ,其左侧边与 x 轴上坐标点 left(i) 对齐。

每个方块都从一个比目前所有的落地方块更高的高度掉落而下。方块沿 y 轴负方向下落,直到着陆到 另一个正方形的顶边 或者是 x 轴上 。一个方块仅仅是擦过另一个方块的左侧边或右侧边不算着陆。一旦着陆,它就会固定在原地,无法移动。

在每个方块掉落后,你必须记录目前所有已经落稳的 方块堆叠的最高高度

返回一个整数数组 ans ,其中 ans[i] 表示在第 i 块方块掉落后堆叠的最高高度。

示例 1:

输入:positions = [[1,2],[2,3],[6,1]] 输出:[2,5,5] 解释: 第 1 个方块掉落后,最高的堆叠由方块 1 组成,堆叠的最高高度为 2 。 第 2 个方块掉落后,最高的堆叠由方块 1 和 2 组成,堆叠的最高高度为 5 。 第 3 个方块掉落后,最高的堆叠仍然由方块 1 和 2 组成,堆叠的最高高度为 5 。 因此,返回 [2, 5, 5] 作为答案。

示例 2:

输入:positions = [[100,100],[200,100]] 输出:[100,100] 解释: 第 1 个方块掉落后,最高的堆叠由方块 1 组成,堆叠的最高高度为 100 。 第 2 个方块掉落后,最高的堆叠可以由方块 1 组成也可以由方块 2 组成,堆叠的最高高度为 100 。 因此,返回 [100, 100] 作为答案。 注意,方块 2 擦过方块 1 的右侧边,但不会算作在方块 1 上着陆。

提示:

  • 1 <= positions.length <= 1000

  • 1 <= left(i) <= 10(8)

  • 1 <= sideLength(i) <= 10(6)

离散化+暴力

1.

对于每一个position值,[1,2]表示[1,1+2]区间上落下一个边长为2的正方形.

[2,3]表示[2,2+3]区间上落下一个边长为3的正方形.

[6,1]表示[6,6+1]区间上落下一个边长为3的正方形.

2.

对于每一个position值,可以抽象出左右边界和正方形的边长.[left,right],边长h.

maxcount数组存储每个点上的最大高度.

由于点没有办法表示图像,长度.因此可以定义index表示[index,index+1)的区间.

maxcount[1]=2,表示[1,2)区间上最大的高度是2.以此类推

那么对于每一个position,position[i][0]==left,position[i][0]+position[i][1]-1==right.边长为position[i][1].

3.

只需要对于每一个position方块,遍历left到right找到最大值记为maxh,此时更新left到right所有值为maxh+position[i][1].

然后把此时所有区间的最大高度值尾插到ret数组中.

因此还需要一个变量存储所有区间的最大高度值.

离散化

1.

我们知道所有方块对应的下标,第一个方块对应的left,right,第二个方块对应的left,right......

将这些下标排序+去重.存储到map中.

也就是直接将这些数据加入到map中即可,因为map自动排序+去重.

2.

将所有需要用到的下标,point加入到map后,依次给这些数据设置映射值,第一个元素映射0,第二个元素映射1,第三个元素映射3,以此类推.

压缩坐标.因为原来的point的值我们并不关心是多少,我们只关心每一个point有一个maxcount记录最大值.

因此对于每一个point映射下标,对应maxcount的下标.

暴力

然后暴力求解即可.

 
class Solution {
public:vector<int> fallingSquares(vector<vector<int>>& positions) {map<int, int> nums_index; // 使用map来记录每个方块的左右边界对应的高度索引vector<int> ret; // 存储结果的数组for (auto& x : positions) {nums_index[x[0]]; // 记录左边界对应的高度索引nums_index[x[0] + x[1] - 1]; // 记录右边界对应的高度索引}int index = 0;for (auto& x : nums_index) {x.second = index++; // 为所有的高度索引分配唯一的编号}vector<int> maxcount(index); // 存储每个高度索引对应的最大高度int maxh = INT_MIN;for (auto& x : positions) {int left = nums_index[x[0]]; // 获取左边界对应的高度索引int right = nums_index[x[0] + x[1] - 1]; // 获取右边界对应的高度索引int max1 = INT_MIN;for (int i = left; i <= right; i++) {max1 = fmax(maxcount[i], max1); // 找到左右边界中的最大高度}int newh = max1 + x[1]; // 计算掉落后的新高度for (int i = left; i <= right; i++) {maxcount[i] = newh; // 更新每个高度索引对应的高度}if (newh > maxh)maxh = newh; // 更新最大高度ret.push_back(maxh); // 将最大高度加入结果数组}return ret; // 返回结果数组}
};

离散化+线段树

线段树

在暴力过程中,我们遍历left到right区间找区间最大值,然后全部加上边长,再把所有区间的最大高度尾插到ret数组中.

我们暴力查询区间max,暴力更新区间所有值.时间复杂度是O(N).

线段树优化这两个过程,线段树区间查询和区间更新操作都是O(logN).

线段树代码分析

1.

成员变量,一般来说要有一个arr数组,对应nums数组,区别是arr数组元素下标从1开始,也就是0位置不用,从1开始的元素依次对应nums数组的值.

size遍历存储数组大小.

treenode表示树的节点信息.

tree表示arr数组对应的线段树结构.

2.

treenode节点信息,maxh对应线段树区间查询的信息.

int change; // 变化值 int isupdate; // 是否需要更新

对应线段树区间更新的操作

表示任务值,和任务是否存在.

3.

pushup函数,用已经维护好的左右孩子信息,维护当前节点的信息.

维护的信息是线段树区间查询的信息.

4.

pushdown函数,用于下发一层任务,如果当前节点有任务,就下发,下发任务需要更新左右孩子的信息.

线段树区间查询的信息以及有关任务的信息.

也就是treenode中所有的信息.

5.

query查询函数,树结构对应是递归函数,用于查询L~R区间中的sum元素和.

如果当前节点对应的区间是L~R的一部分,返回当前节点的sum值.

如果当前节点和L~R没有重叠,return 0.

如果当前节点和L~R有一部分重叠,return 左孩子中某个节点区间是L~R一部分的sum值.或者renturn 右孩子中某一个节点区间是L~R一部分的sum值.

请注意,确保能够准确的实现递归逻辑,递归查询,去孩子节点查询的时候,必须把当前任务下发.如果有任务就下发,没有任务就不下发.

6.

update区间更新函数,树结构对应是递归函数,用于表示L~R区间更新为C.

如果当前节点对应的区间是L~R的一部分,维护当前节点所有查询信息和此次操作的信息.

如果当前节点和L~R没有重叠,return .表示不需要维护信息

如果当前节点和L~R有一部分重叠,更新左子树,更新右子树,更新自己.

同样的更新左右子树的时候,需要把旧任务下发一层.再更新

 
class SegmentTree {
public:int size; // 线段树数组的大小struct treenode {int maxh; // 节点对应的最大高度int change; // 变化值int isupdate; // 是否需要更新};vector<treenode> tree; // 线段树节点数组void pushup(int i) { // 更新父节点的最大高度tree[i].maxh = max(tree[i << 1].maxh, tree[i << 1 | 1].maxh);}void pushdown(int i) { // 下推更新if (tree[i].isupdate) {tree[i << 1].maxh = tree[i << 1 | 1].maxh = tree[i].change;tree[i << 1].change = tree[i << 1 | 1].change = tree[i].change;tree[i << 1].isupdate = tree[i << 1 | 1].isupdate = true;tree[i].isupdate = false;}}int query(int L, int R) { // 查询return _query(L + 1, R + 1, 1, size - 1, 1);}
private:int _query(int L, int R, int l, int r, int rt) { // 内部查询函数if (r < L || R < l) return 0;if (L <= l && r <= R) {return tree[rt].maxh;}pushdown(rt);int mid = (l + r) >> 1;return max(_query(L, R, l, mid, rt << 1), _query(L, R, mid + 1, r, rt << 1 | 1));}
public:void update(int L, int R, int C) { // 更新_update(L + 1, R + 1, C, 1, size - 1, 1);}
private:void _update(int L, int R, int C, int l, int r, int rt) { // 内部更新函数if (r < L || R < l) return;if (L <= l && r <= R) {tree[rt].maxh = C;tree[rt].isupdate = true;tree[rt].change = C;return;}pushdown(rt);int mid = (l + r) >> 1;_update(L, R, C, l, mid, rt << 1);_update(L, R, C, mid + 1, r, rt << 1 | 1);pushup(rt);}
public:SegmentTree(int n) { // 构造函数size = n + 1;tree.resize(size << 2);}
};class Solution {
public:vector<int> fallingSquares(vector<vector<int>>& positions) {// 初始化操作int n = positions.size();map<int, int> point_index; // 统计点的索引for (auto& x : positions) {point_index[x[0]];point_index[x[0] + x[1] - 1];}int index = 0;for (auto& x : point_index) {x.second = index++;}SegmentTree t(point_index.size()); // 初始化线段树// 开始解题vector<int> ret; // 存储结果的数组int maxh = INT_MIN;for (auto& x : positions) {int left = point_index[x[0]]; // 获取左边界对应的高度索引int right = point_index[x[0] + x[1] - 1]; // 获取右边界对应的高度索引int h = x[1]; // 方块高度int cur_maxHight = t.query(left, right); // 查询当前区间的最大高度cur_maxHight = cur_maxHight + h; // 计算新高度maxh = max(maxh, cur_maxHight); // 更新最大高度ret.push_back(maxh); // 将最大高度加入结果数组t.update(left, right, cur_maxHight); // 更新区间}return ret; // 返回结果数组}
};

结尾

最后,感谢您阅读我的文章,希望这些内容能够对您有所启发和帮助。如果您有任何问题或想要分享您的观点,请随时在评论区留言。

同时,不要忘记订阅我的博客以获取更多有趣的内容。在未来的文章中,我将继续探讨这个话题的不同方面,为您呈现更多深度和见解。

谢谢您的支持,期待与您在下一篇文章中再次相遇!

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

[Meachines][Easy]Bizness

Main $ nmap -p- 10.10.11.252 --min-rate 1000 $ dirsearch -u https://bizness.htb/ $ whatweb https://bizness.htb/control/login 存在一个未授权的RCE $ git clone https://github.com/jakabakos/Apache-OFBiz-Authentication-Bypass.git $ cd Apache-OFBiz-Authenticat…

网络爬虫快速入门及爬取百度搜索结果(附源码)

前言 爬虫的基本结构及工作流程 1. 确定目标 首先&#xff0c;确定你想要爬取的目标&#xff0c;包括目标网站或网页、需要提取的数据类型&#xff08;如文本、图片、视频等&#xff09;以及爬取的深度&#xff08;单页、整个网站等&#xff09;。 2. 获取网页内容 使用HT…

STM32单片机C语言模块化编程实战:按键控制LED灯并串口打印详解与示例

一、开发环境 硬件&#xff1a;正点原子探索者 V3 STM32F407 开发板 单片机&#xff1a;STM32F407ZGT6 Keil版本&#xff1a;5.32 STM32CubeMX版本&#xff1a;6.9.2 STM32Cube MCU Packges版本&#xff1a;STM32F4 V1.27.1 虽然这里演示的是STM32F407&#xff0c;但是ST…

数控6面钻的优缺点

在木工、家具制造和建筑行业中&#xff0c;数控6面钻已成为一种革命性的工具。这种先进的机器以其高效、精准和多功能性受到了广大制造商的青睐。然而&#xff0c;就像任何技术产品一样&#xff0c;数控6面钻也有其优缺点。在本文中&#xff0c;我们将深入探讨数控6面钻的优缺点…

20240423给飞凌的OK3588-C开发板适配OV13855【绿屏】查找问题

20240423给飞凌的OK3588-C开发板适配OV13855【绿屏】查找问题 2024/4/23 19:43 修改2个部分&#xff1a; 1、DTS中CAM1由ISP0处理修改为ISP1处理。【感觉修改为ISP1之后就不出错了&#xff0c;难道ISP0有问题&#xff1f;】 2、ov13855.c修改为 荣品的RK3588开发板提供的SDK An…

等级保护详解:企业为何需要等级保护及等保测评的重要性

在信息化高速发展的今天&#xff0c;网络安全问题日益凸显&#xff0c;各类网络安全事件频发&#xff0c;给企业和个人带来了极大的损失。为了加强网络安全管理&#xff0c;提高网络安全防护能力&#xff0c;我国推出了网络安全等级保护制度&#xff0c;简称“等保”。那么&…

Fisher判别:理解数据分类的经典方法

在机器学习和统计分类的领域中&#xff0c;Fisher判别&#xff08;也称为Fisher线性判别分析&#xff09;是一种非常重要的方法&#xff0c;旨在从数据中提取重要特征&#xff0c;以实现对样本的分类。即Fisher判别分析&#xff08;Fisher Discriminant Analysis, FDA&#xff…

【数据结构】stack queue —— 栈和队列

前言 这阵子一直在学数据结构&#xff0c;知识点消化地有点慢导致博客一直没写&#xff0c;现在总算是有时间歇下来补补前面落下的博客了。从现在起恢复周更&#xff0c;努努力一周两篇也不是梦……闲话少说&#xff0c;今天就让我们一起来认识栈和队列 1. 栈的介绍和使用 栈…

模块三:二分——69.x的平方根

文章目录 题目描述算法原理解法一&#xff1a;暴力查找解法二&#xff1a;二分查找 代码实现暴力查找CJava 题目描述 题目链接&#xff1a;69.x的平方根 算法原理 解法一&#xff1a;暴力查找 依次枚举 [0, x] 之间的所有数 i &#xff08;这⾥没有必要研究是否枚举到 x /…

基于Linux系统命令行安装KingbaseES数据库

人大金仓通用性数据库&#xff08;Kingbase&#xff09;下载网址&#xff1a;人大金仓-成为世界卓越的数据库产品与服务提供商 选择“软件版本-数据库”&#xff0c;筛选条件Linux、完整版。找到需要的版本&#xff0c;点击下载。我下载的是KingbaseES_V008R006C008B0014_Lin6…

初入单元测试

单元测试&#xff1a;针对最小的功能单元(方法)&#xff0c;编写测试代码对其进行正确性测试 Junit可以用来对方法进行测试&#xff0c;虽然是有第三方公司开发&#xff0c;但是很多开发工具已经集成了&#xff0c;如IDEA。 Junit 优点&#xff1a;可以灵活的编写测试代码&am…

基础SQL DQL语句

基础查询 select * from 表名; 查询所有字段 create table emp(id int comment 编号,workno varchar(10) comment 工号,name varchar(10) comment 姓名,gender char(1) comment 性别,age tinyint unsigned comment 年龄,idcard char(18) comment 身份证号,worka…

yolov8使用pycharm用代码训练连续运行问题 RuntimeError

背景&#xff1a;PyCharm下使用代码运行yolov8 问题描述 连续运行两次导致进程冲突 RuntimeError 原因&#xff1a;在当前进程完成引导阶段之前&#xff0c;试图启动新的子进程。 RuntimeError: An attempt has been made to start a new process before the current proces…

【Nginx】centos和Ubuntu操作系统下载Nginx配置文件并启动Nginx服务详解

目录 &#x1f337; 安装Nginx环境 &#x1f340; centos操作系统 &#x1f340; ubuntu操作系统 &#x1f337; 安装Nginx环境 以下是在linux系统中安装Nginx的步骤&#xff1a; 查看服务器属于哪个操作系统 cat /etc/os-release安装 yum&#xff1a; 如果你确定你的系统…

【经验分享】Ubuntu22.04安装微信(linux官方版)

【经验分享】Ubuntu22.04安装微信linux官方版 前言安装方法效果展示总结 前言 最近腾讯推出了linux官方版微信wechat&#xff0c;但是仅支持国产系统麒麟和统信UOS&#xff0c;这对使用Ubuntu的小伙伴可不太友好&#xff0c;打算装个试试&#xff0c;在网上搜了下终于找到快捷…

验证 python解释器是否安装成功

一. 简介 前一篇文章学习了下载并安装 python解释器&#xff0c;文章如下&#xff1a; windows系统下python解释器安装-CSDN博客 本文验证 python解释器是否安装成功。 二. 验证 python解释器是否安装成功 1. 首先&#xff0c;打开 Windows系统的 "cmd" 界面。…

SD-WAN制造业网络优化方案

制造业在数字化浪潮的推动下&#xff0c;进行转型的需求越来越强烈。网络作为制造业数字化转型的关键基础设施&#xff0c;其稳定性、安全性和灵活性直接影响着企业的运营效率和市场竞争力。而SD-WAN可以为制造业提供有效的解决方案&#xff0c;让制造业顺利高效地进行数字化转…

内插和抽取

抽取&#xff1a; 频域表达式的关系&#xff1a; 1、角频率扩大M倍 2、移动2pi、22pi…&#xff08;n-1&#xff09; 2pi 3、相加 4、幅度变为1/M 内插&#xff1a; 加入低通滤波&#xff0c;减小混叠&#xff0c;但是由于截短&#xff0c;也会造成误差&#xff0c;但是…

投资网站汇总

1、 中信证券(600030)历年财务指标——亿牛网https://eniu.com/gu/sh600030/cwzb 2、 3、 4、

DFS与回溯专题:路径总和问题

DFS与回溯专题&#xff1a;路径总和问题 一、路径总和 题目链接&#xff1a; 112.路径总和 题目描述 代码思路 对二叉树进行dfs搜索&#xff0c;递归计算每条路径的节点值之和&#xff0c;当某个节点的左右子节点都为空时&#xff0c;说明已经搜索完成某一条路径&#xff0…