【Leetcode】699. 掉落的方块(困难)

news2025/1/16 14:04:09

一、题目

1、题目描述

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

给你一个二维整数数组 positions ,其中 p o s i t i o n s [ i ] = [ l e f t i , s i d e L e n g t h i ] positions[i] = [left_i, sideLength_i] positions[i]=[lefti,sideLengthi] 表示:第 i 个方块边长为 s i d e L e n g t h i sideLength_i sideLengthi ,其左侧边与 x 轴上坐标点 l e f t i left_i lefti 对齐。

每个方块都从一个比目前所有的落地方块更高的高度掉落而下。方块沿 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 上着陆。

2、基础框架

class Solution {
public:
    vector<int> fallingSquares(vector<vector<int>>& positions) {

    }
};

3、原题链接

699. 掉落的方块

二、解题报告

1、思路分析

利用线段树
题目分析:比如第一个方块[1,2],对应成线段树就是区间[1, 3) (靠着1,长度为2,所以能到达x轴的3位置,但是为了防止贴边,所以区间左闭右开)每个位置的值加2。

在这里插入图片描述
如果有一个新的方块落下来[left, sideLength],要先查询 [left, left + sideLength) 这个范围上的最大高度值 maxH,就知道落到这个高度后不能往下再落了,将[left, left + sideLength]区间上的所有高度全部更新为 maxH + sideLength,这个区间上原先的值为多少不再关心。

整体而言,就是一个 更新 + 查询max的线段树

2、时间复杂度

O ( n l o g n ) O(nlogn) O(nlogn)

3、代码详解

  • C++
class Solution {
public:
    class SegmentTree {
    private:
        int *maxH;
        int *change;
        bool *updateMark;

    public:
        //线段树初始化
        SegmentTree(int size) { //x轴上的数开始都为0,不存在数组
            int n = size + 1;
            maxH = new int[n << 2]();
            change = new int[n << 2]();
            updateMark = new bool[n << 2]();
        }

    private:
        //根节点的最大值
        void pushUp(int rt) { 
            maxH[rt] = max(maxH[rt << 1], maxH[rt << 1 | 1]); //从左右子树中得到最大值
        }    

        //向下一级分发任务
        void pushDown(int rt, int ln, int rn) {
            if (updateMark[rt]) {
                updateMark[rt << 1] = true;
                updateMark[rt << 1 | 1] = true;
                change[rt << 1] = change[rt];
                change[rt << 1 | 1] = change[rt];
                maxH[rt << 1] = change[rt];
                maxH[rt << 1 | 1] = change[rt];
                updateMark[rt] = false;
            }
        }

    public:
        //更新
        void update(int L, int R, int C, int l, int r, int rt) {
            if (L <= l && r <= R) {
                change[rt] = C;
                updateMark[rt] = true;
                maxH[rt] = C;
                return ;
            }

            int mid = (l + r) >> 1;
            pushDown(rt, mid - l + 1, r - mid);
            if (L <= mid) {
                update(L, R, C, l, mid, rt << 1);
            }

            if (R > mid) {
                update(L, R, C, mid + 1, r, rt << 1 | 1);
            }

            pushUp(rt);
        }

        //查询
        int query(int L, int R, int l, int r, int rt) {
            if (L <= l && r <= R) {
                return maxH[rt];
            }
            int left = 0;
            int right = 0;
            int mid = (l + r) >> 1;
            pushDown(rt, mid - l + 1, r - mid);
            if (L <= mid) {
                left = query(L, R, l, mid, rt << 1);
            }

            if (R > mid) {
                right = query(L, R, mid + 1, r, rt << 1 | 1);
            }

            return max(left, right);
        }
    };

    unordered_map<int, int> index(vector<vector<int>>& positions) {
        set<int> pos;
        for (vector<int> &arr: positions) {
            pos.insert(arr[0]);
            pos.insert(arr[0] + arr[1] - 1);
        }

        unordered_map<int, int> _map;
        int count = 0;
        for (int index : pos) {
            _map[index] = ++count;
        }
        
        return _map;
    }

    vector<int> fallingSquares(vector<vector<int>>& positions) {
        unordered_map<int, int> _map = index(positions);
        int n = _map.size();

        SegmentTree *st = new SegmentTree(n);

        int maxH = 0;

        vector<int> res;
        for (vector<int> &arr : positions) {
            int L = _map[arr[0]];
            int R = _map[arr[0] + arr[1] - 1]; 
            int height = st->query(L, R, 1, n, 1) + arr[1]; 
            maxH = max(maxH, height);
            res.push_back(maxH);
            st->update(L, R, height, 1, n, 1);
        }
        return res;
    }
};
  • Java
class Solution {
    public static class SegmentTree {
		private int[] max;
		private int[] change;
		private boolean[] update;

		public SegmentTree(int size) {
			int N = size + 1;
			max = new int[N << 2];

			change = new int[N << 2];
			update = new boolean[N << 2];
		}

		private void pushUp(int rt) {
			max[rt] = Math.max(max[rt << 1], max[rt << 1 | 1]);
		}

		// ln表示左子树元素结点个数,rn表示右子树结点个数
		private void pushDown(int rt, int ln, int rn) {
			if (update[rt]) {
				update[rt << 1] = true;
				update[rt << 1 | 1] = true;
				change[rt << 1] = change[rt];
				change[rt << 1 | 1] = change[rt];
				max[rt << 1] = change[rt];
				max[rt << 1 | 1] = change[rt];
				update[rt] = false;
			}
		}

		public void update(int L, int R, int C, int l, int r, int rt) {
			if (L <= l && r <= R) {
				update[rt] = true;
				change[rt] = C;
				max[rt] = C;
				return;
			}
			int mid = (l + r) >> 1;
			pushDown(rt, mid - l + 1, r - mid);
			if (L <= mid) {
				update(L, R, C, l, mid, rt << 1);
			}
			if (R > mid) {
				update(L, R, C, mid + 1, r, rt << 1 | 1);
			}
			pushUp(rt);
		}

		public int query(int L, int R, int l, int r, int rt) {
			if (L <= l && r <= R) {
				return max[rt];
			}
			int mid = (l + r) >> 1;
			pushDown(rt, mid - l + 1, r - mid);
			int left = 0;
			int right = 0;
			if (L <= mid) {
				left = query(L, R, l, mid, rt << 1);
			}
			if (R > mid) {
				right = query(L, R, mid + 1, r, rt << 1 | 1);
			}
			return Math.max(left, right);
		}

	}

    public HashMap<Integer, Integer> index(int[][] positions) {
		TreeSet<Integer> pos = new TreeSet<>();
		for (int[] arr : positions) {
			pos.add(arr[0]);
			pos.add(arr[0] + arr[1] - 1);
		}
		HashMap<Integer, Integer> map = new HashMap<>();
		int count = 0;
		for (Integer index : pos) {
			map.put(index, ++count);
		}
		return map;
	}

    public List<Integer> fallingSquares(int[][] positions) {
        HashMap<Integer, Integer> map = index(positions);
		int N = map.size();
		SegmentTree segmentTree = new SegmentTree(N);
		int max = 0;
		List<Integer> res = new ArrayList<>();
		// 每落一个正方形,收集一下,所有东西组成的图像,最高高度是什么
		for (int[] arr : positions) {
			int L = map.get(arr[0]);
			int R = map.get(arr[0] + arr[1] - 1);
			int height = segmentTree.query(L, R, 1, N, 1) + arr[1];
			max = Math.max(max, height);
			res.add(max);
			segmentTree.update(L, R, height, 1, N, 1);
		}
		return res;
    }
}

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

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

相关文章

基于YOLOV5的手势识别系统源码及模型,训练得到能识别10种常用手势的模型

毕设系列-基于YOLOV5的手势识别系统 完整代码下载地址&#xff1a;基于YOLOV5的手势识别系统源码及模型 本期我们带来的内容是基于YOLOV5的手势识别系统&#xff0c;我们将会训练得到能识别10种常用手势的模型&#xff0c;废话不多说&#xff0c;还是先看效果。 配置环境 不熟…

ROS2 Launch文件编辑及运行

在第一版的 ROS 中launch 一般使用 xml 文件的格式进行编写和运行&#xff0c;但从 ROS2 中增添了 py 的 python 的可执行文件 作用 为了解决频繁的 ros2 run 命令&#xff0c;和多个节点之间的运行及关闭 特性 launch文件允许我们同时启动和配置多个包含 ROS 2 节点的可执行…

Java学习者看过来。。。这些优质项目千万别错过

程序员宝藏库&#xff1a;https://gitee.com/sharetech_lee/CS-Books-Store 这么主流的编程语言&#xff0c;如果去GitHub搜一下&#xff0c;会发现Java项目多如牛毛。 这就会带来很多困扰&#xff0c;假如有10万个项目&#xff0c;想从其中找到适合初学、进阶等不同阶段的项目…

【OpenFOAM】-olaFlow-算例7-波面自适应网格

算例路径&#xff1a; none 算例描述&#xff1a; 波面附近采用自适应网格划分 学习目标&#xff1a; 动网格设置和使用&#xff0c;dynamicFvMesh dynamicRefineFvMesh 的各参数含义 学习体会&#xff1a;    (1) 在结构附近的加密网格&#xff0c;自适应网格依然会对细网格…

weston 窗口管理 (1)

窗口管理 (1) 一、概述 在传统嵌入式场景下,通常只会运行一个UI程序,故相当于单窗口程序,无需桌面服务器的介入;在桌面系统下,对于每一个UI程序而言,它们的行为相比于嵌入式场景仍然没有发生改变,其对接的仍然是窗口,只不过在同一个时刻允许多个UI程序同时运行. 无论如何对于…

Git的标签:tag

目录 1. 查看标签 1.1 简单查看 1.2 匹配筛选标签 2. 创建标签 2.1 附注标签 2.2 轻量标签 2.3 代码提交之后打标签 2.4 提交标签 3. 删除标签 4. 检出标签 Git 可以给仓库历史中的某一个提交打上标签&#xff0c;以示重要。 比较有代表性的是人们会使用这个功能来标记…

thrift OOM 内存溢出

最近经常发生thrift服务半夜宕机的问题&#xff0c;虽然是测试环境&#xff0c;但是每天早上重启也很恶心。 经过很长时间的摸索&#xff0c;终于找到了原因。先说背景&#xff1a; 我们用的thrift版本是0.9.2&#xff0c;用做service的rpc框架&#xff0c;某一天开始&#x…

安全狗云原生安全产品入选《2022网络安全技术应用试点示范项目名单》

近日&#xff0c;工信部正式发布《2022网络安全技术应用试点示范项目名单》。作为国内云原生安全领导厂商&#xff0c;安全狗也凭借突出的产品能力&#xff0c;入选名单。 据悉&#xff0c;此次评选需层层通过单位申报、部门初审和推荐、专家评审、网上公示等多个环节。安全狗…

玉湖冷链黄铮洪出任广东省物流标准化技术委员会副主任

1月5日&#xff0c;广东省物流标准化技术委员会(第三届)成立大会召开&#xff0c;玉湖冷链执行董事黄铮洪出任副主任委员。 大会现场 根据2022年9月广东省市场监督管理局发布的通告&#xff0c;决定成立第三届广东省物流标准化技术委员会(以下简称「标准化委员会」)。此次大会进…

七、k8s Service详解

文章目录1 Service介绍1.1 userspace 模式1.2 iptables 模式1.3 ipvs 模式2 Service类型3 Service使用3.1 实验环境准备3.2 ClusterIP类型的Service3.3 Endpoint3.4 HeadLiness类型的Service3.5 NodePort类型的Service3.6 LoadBalancer类型的Service3.7 ExternalName类型的Serv…

树莓派3B摄像头的详细使用教程(拍照+录像+监控)

树莓派4B摄像头的详细使用教程&#xff08;拍照录像监控&#xff09; 本篇博文将介绍树莓派摄像头是如何在树莓派开发板上从安装到使用的&#xff0c;博主过程中参考了许多帖子&#xff0c;现将整理的比较全面的过程分享出来&#xff0c;供大家参考使用。 排线连接 硬件连接时…

【阶段二】Python数据分析数据可视化工具使用02篇:条形图与雷达图

本篇的思维导图: 条形图 条形图与柱形图类似,几乎可以表达相同多的数据信息。条形图的柱形变为横向,从而导致与柱形图相比,条形图更加强调项目之间的大小对比。尤其在项目名称较长以及数量较多时,采用条形图可视化数据会更加美观、清晰。 代码 # 导入需要的包imp…

java学习day70(乐友商城)授权中心

1.无状态登录原理 1.1.什么是有状态&#xff1f; 有状态服务&#xff0c;即服务端需要记录每次会话的客户端信息&#xff0c;从而识别客户端身份&#xff0c;根据用户身份进行请求的处理&#xff0c;典型的设计如tomcat中的session。 例如登录&#xff1a;用户登录后&#x…

cubeIDE开发, stm32的C库应用分析

一、stm32的C库 cubeIDE针对STM32芯片开发&#xff0c;提供个了两大库&#xff0c;HLA库和C库&#xff08;集成GNU Tools for STM32工具链时提供&#xff0c;该工具链同样是意法半导体提供&#xff0c;可在http:// www.st.com单独下载&#xff09;&#xff0c;前者帮助开发这简…

P1055 [NOIP2008 普及组] ISBN 号码————C++

文章目录题目[\[NOIP2008 普及组\] ISBN 号码](https://www.luogu.com.cn/problem/P1055)题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1样例 #2样例输入 #2样例输出 #2提示解题思路1Code运行结果解题思路2Code运行结果题目 [NOIP2008 普及组] ISBN 号码 题目描述 …

windows 安装jenkins运行发布vue项目到linux服务器

文章目录背景安装jenkins安装插件安装nodej插件Publish over SSH系统配置Publish over SSH全局工具配置设置node构建项目创建一个freestyle的项目Discard old buildsgit命令报错Host key verification failedBuild背景 由于服务器上运行jenkins很卡&#xff0c;所以对于小公司…

windows安装jenkins运行发布java springboot项目到linux服务器

文章目录背景安装jenkins安装插件安装maven插件Publish over SSH系统配置Global propertiesPublish over SSH全局工具配置设置jdk设置maven设置git构建java maven项目freestyle 或者maven都可以Discard old buildsgit命令报错Host key verification failed每次构建前清理构建环…

可观测性之Log4j2优雅日志打印

可观测性之Log4j2优雅日志打印# 简介 对于Log4j2大家应该都不是很陌生&#xff0c;听说最多的应该是2021年年底出现的安全漏洞了&#xff0c;不过最让大家头痛的应该不仅仅是这个安全漏洞的处理&#xff0c;安全漏洞通过升级最新的依赖版本即可快速解决&#xff0c;平时在使用…

基于Java+SpringMvc+vue+element实现上海汽车博物馆平台

基于JavaSpringMvcvueelement实现上海汽车博物馆平台 博主介绍&#xff1a;5年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 超级帅帅吴 Java毕设项目精品实战案例《500套》 欢迎点赞 收藏 ⭐留言 文末获取源…

C语言.表白神器.爱你之心之闪耀

前言 爱你之心之闪耀&#xff0c;这个名字比较沙雕哈哈哈。。。 爱你之心之闪耀前言爱心函数的选取爱心函数1爱心函数2简单爱心粒子发射原理爱心结构一些宏初始化init创建若干爱心并初始化setHeart展示爱心showHeart爱心变大modifyHeart设置音乐主函数Love.hLove.cpp祝有情人&a…