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

news/2024/7/24 2:09:10 标签: leetcode, 线段树

一、题目

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.niftyadmin.cn/n/24776.html

相关文章

SwitchResX for Mac 屏幕分辨率修改工具

前言 SwitchResX V4.12.1 是Mac上一款功能强大的屏幕分辨率修改软件&#xff0c;可以为您提供控制显示器分辨率所需的所有工具。在switchresx帮助下&#xff0c;您可以管理无论是Mac Retina显示器&#xff0c;Cinema Displays还是电视机甚至投影仪的任何分辨率。而且switchres…

干货|app自动化测试之Appium WebView 技术原理

混合应用测试或微信小程序测试&#xff0c;都会涉及到 WebView 组件&#xff0c;这节内容将分析一下 WebView 的技术原理。首先通过日志分析查看 Appium 的运行过程。WebView日志分析要想查看 ChromeDriver 的日志&#xff0c;需要在 Capability 里开启 一个开关项 showChromed…

数据的存储(C语言)

数据类型&#xff1a; 要了解数据是如何存储的&#xff0c;我们就得先知道C语言中的数据类型 基本数据类型 基本数据类型&#xff0c;也就是C语言内置类型&#xff1a; char -> 字符型 short -> 短整型 int -> 整…

高性能存储SIG月度动态:DSMS开始适配Anolis OS、将在ANCK 5.10中支持ublk | 龙蜥 SIG

高性能存储技术 SIG 目标&#xff1a;高性能存储技术兴趣组致力于存储栈性能挖掘&#xff0c;当前主要聚焦内核 io_uring 技术优化异步 IO 性能&#xff0c;使用持久化内存提升业务单成本性能&#xff0c;容器场景存储技术优化等课题。期望通过社区平台&#xff0c;打造标准的高…

Java面向对象:封装、JavaBean和综合案例

目录封装基本概念总结如何更好的封装总结JavaBean补充知识&#xff1a;成员变量&#xff0c;局部变量区别综合案例封装 面向对象的三大特征:封装&#xff0c;继承&#xff0c;多态。 封装:告诉我们&#xff0c;如何正确设计对象的属性和方法。 封装的原则:对象代表什么&#x…

股票实盘量化交易之所以受普通投资者欢迎有哪两大原因?

股票实盘量化交易之所以如此受普通投资者欢迎&#xff0c;还有以下2个原因&#xff1a; 1、零成本试错&#xff0c;全市场捕捉赚钱机会 一般来说&#xff0c;大家都是拿真金白银去股票市场冒险的&#xff0c;风险极高&#xff0c;但如果你会量化交易&#xff0c;大可不必拿自己…

一、mysql基础、MySQL的安装及卸载、DML、DQL

MySQL基础 1、数据库相关概念 以前我们做系统&#xff0c;数据持久化的存储采用的是文件存储。存储到文件中可以达到系统关闭数据不会丢失的效果&#xff0c;当然文件存储也有它的弊端。 假设在文件中存储以下的数据&#xff1a; 姓名 年龄 性别 住址 张三 23 男 北京西三…

在有限和无限图上计算simulations

摘要 我们展示了用于计算带有标签的图的相似性的算法。相似关系适用于不同的激活系统模式。对于有限图&#xff0c;我们提出了一种用于计算n个点m条边的图&#xff08;假设m≥nm\ge nm≥n&#xff09;的相似关系的O(mn)算法。为了高效地表示无限图&#xff0c;我们提出了一个标…